This is a peer-to-peer client server code to run on Winodws. It will require a winsock2 lib
/*
Developer: Al Sabawi -- Vestal NY
Reqs: Windows VC++ compiler + winsock.lib
simple threaded server in the internet domain using TCP
-- peer-to-peer communication port number is hardcoded to 8808
-- broadcast and discovery port number is hard coded to 8809
*/
#include <stdio.h>
#include <Winsock2.h>
#include <sys/types.h>
#include < time.h >
//#include <sys/socket.h>
//#include <netinet/in.h>
#define bzero ZeroMemory
const int portno=8808;
const int broadcast_portno = 8809;
//=======================================================================
// Function : broadcast_thread
// in : none
// return : none
// Description: To be forked in its own thread to send out a broadcast to the local subnet
// the current broadcast message is <myhostname:my.ip.address.dotted>
//
void broadcast_thread(void)
{
unsigned int tbcaddr; // The broadcast address.
short port; // The port for the broadcast.
struct sockaddr_in bcLocal; // local socket address for the broadcast.
struct sockaddr_in bcaddr; // The broadcast address for the receiver.
SOCKET bcfd; // The socket used for the broadcast.
BOOL one = TRUE; // Parameter for "setscokopt".
int pn; // The number of the packet broadcasted.
char buff[1024]; // Buffers the data to be broadcasted.
char myhostname[100]; // hostname of local machine
char myhostaddr[100]; // host address of local machine
char subnetmask[100]; // Subnet mask to broadcast to
struct in_addr myaddr; // My host address in net format
struct hostent* myhostent;
char * ptr; // some transient vars
int len,i;
/* get my host name */
gethostname(myhostname,100);
myhostent = gethostbyname(myhostname);
// get only the first host IP address
sprintf(myhostaddr, "%s\n",inet_ntoa(*(struct in_addr *)myhostent->h_addr_list[0]));
strcpy(subnetmask, myhostaddr);
ptr = &subnetmask[0];
len = strlen(ptr);
// substitute the address with class C subnet mask x.x.x.255
for(i=len;i>0;i--)
{
if(ptr[i] == '.')
{
strcpy(&ptr[i+1],"255");
break;
}
}
// Convert the broadcast address from dot notation to a broadcast address.
if( (tbcaddr = inet_addr( subnetmask )) == INADDR_NONE )
{
printf("Badly formatted BC address: %d\n", WSAGetLastError());
exit(-1);
}
port = htons( broadcast_portno );
// Create the broadcast socket
memset( &bcLocal, 0, sizeof( struct sockaddr_in));
bcLocal.sin_family = AF_INET;
bcLocal.sin_addr.s_addr = htonl( INADDR_ANY );
bcLocal.sin_port = htons( 0 ); // We are letting the OS fill in the port number for the local machine.
bcfd = socket( AF_INET, SOCK_DGRAM, 0 );
// If there is an error, report it and terminate.
if( bcfd == INVALID_SOCKET )
{
printf("Unable to allocate broadcast socket.: %d\n", WSAGetLastError());
exit(-1);
}
// Mark the socket for broadcast.
if( setsockopt( bcfd, SOL_SOCKET, SO_BROADCAST, (const char *) &one, sizeof( int ) )
== SOCKET_ERROR )
{
printf("Could not set socket to broadcast.: %d\n", WSAGetLastError());
exit(-1);
}
// Bind the address to the broadcast socket.
if(bind(bcfd, (struct sockaddr *) &bcLocal, sizeof(struct sockaddr_in)) == SOCKET_ERROR)
{
printf("Could not bind address to BC socket.: %d\n", WSAGetLastError());
exit(-1);
}
// Record the broadcast address of the receiver.
bcaddr.sin_family = AF_INET;
bcaddr.sin_addr.s_addr = tbcaddr;
bcaddr.sin_port = port;
// Send this machine's host name and address in hostname:n.n.n.n format
for( pn = 1; ; pn++ )
{
Sleep( 1000 ); // send out broadcast every 10 seconds
gethostname(myhostname,100);
myhostent = gethostbyname(myhostname);
sprintf(myhostaddr, "%s\n",inet_ntoa(*(struct in_addr *)myhostent->h_addr_list[0]));
sprintf(buff,"%s:%s",myhostname,myhostaddr);
// Broadcast the packet to the subnet
if( sendto( bcfd, buff, sizeof(buff) + 1, 0 , (struct sockaddr *)&bcaddr
, sizeof(struct sockaddr_in) ) != sizeof(buff) + 1 )
{
printf("Sendto error: %d\n", WSAGetLastError());
exit(-1);
}
else
printf("Broadcasting to %s the message: %s\n",subnetmask,buff);
}
}
//=======================================================================
// Function : discovery_response_thread
// in : none
// return : none
// Description: To be forked in its own thread to listen and respond to broadcasts from
// other servers
//
void discovery_response_thread(void )
{
short port; // The port for the broadcast.
struct sockaddr bcSender; // local socket address for the broadcast.
struct sockaddr_in bcaddr; // The broadcast address for the receiver.
SOCKET bcfd; // The file descriptor used for the broadcast.
BOOL one = TRUE; // Parameter for "setscokopt".
char buff[10024]; // Buffers the data to be broadcasted.
int alen;
int nb; // The number of bytes read.
port = htons( broadcast_portno );
// Prepare to receive the broadcast.
bcfd = socket(AF_INET, SOCK_DGRAM, 0);
if( bcfd == INVALID_SOCKET )
{
printf("socket failed: %d\n", WSAGetLastError());
exit(-1);
}
// Create the address we are receiving on.
memset( (char*)&bcaddr, 0, sizeof(bcaddr));
bcaddr.sin_family = AF_INET;
bcaddr.sin_addr.s_addr = htonl(INADDR_ANY);
bcaddr.sin_port = port;
if(bind( bcfd, (struct sockaddr *)&bcaddr, sizeof(bcaddr) ) == SOCKET_ERROR )
{
printf("bind failed: %d\n", WSAGetLastError());
exit(-1);
}
// Keep getting packets forever.
for( ; ; )
{
alen = sizeof(struct sockaddr);
if( (nb = recvfrom(bcfd, buff, 10024, 0, (struct sockaddr *) &bcSender, &alen)) == SOCKET_ERROR )
{
printf("recvfrom failed: %d\n", WSAGetLastError());
exit(-1);
}
printf( "messages received: %s\n", buff );
}
}
//=======================================================================
// Function : client_thread
// in : int socket from the server to communicate with a single client
// return : none
// Description: To be forked in its own thread to exchange TCP packets with a remote client
// uses non-blocking sock option
//
void client_thread( int newsockfd)
{
int n;
char buffer[2048];
char msg[500];
unsigned long argp = 1;
int rcv_ret = 0;
time_t ltime;
bzero(buffer,2048);
n = ioctlsocket(newsockfd,FIONBIO,&argp);
if (n == SOCKET_ERROR)
{
printf("ioctlsocket failed: %d\n", WSAGetLastError());
exit(-1);
}
// receive and send to peer
while (1)
{
rcv_ret = recv(newsockfd, buffer, 2048, 0);
if (rcv_ret == SOCKET_ERROR)
{
if(WSAGetLastError() == WSAEWOULDBLOCK)
{
// more data could be coming -- we continue to recv
continue;
}
else
{
// recv failed to terminate and exit
printf("recv failed: %d\n", WSAGetLastError());
printf("Terminating connection\n");
break;
}
}
if(rcv_ret == 0) // remote peer closed the socket -- we exit the thread
{
printf("Remote peer closed connection -- Exiting\n");
break;
}
else if (rcv_ret > 0) // we got data
{
printf("received data = %d\n", rcv_ret);
printf("Here is the message: %s\n",buffer);
*buffer = buffer[rcv_ret];
time(<ime);
sprintf(msg,"Hello, My time is %s",ctime( <ime ));
n = send(newsockfd,msg,strlen(msg),0);
if (n < 0)
{
printf(" send() error:%d", WSAGetLastError());
exit(-1);
}
continue;
}
}
n = shutdown(newsockfd, 0);
if (n == SOCKET_ERROR)
{
printf("shutdown failed: %d\n", WSAGetLastError());
closesocket(newsockfd);
WSACleanup();
return ;
}
else
printf("closed connection\n");
return ;
}
//=======================================================================
// Function : server_thread
// in : int socket from the server to communicate with a single client
// return : none
// Description: To be forked in its own thread to exchange TCP packets with a remote client
// uses non-blocking sock option
//
void server_thread(void)
{
int ret;
int sockfd, newsockfd, clilen;
struct sockaddr_in serv_addr, cli_addr;
DWORD ThreadId;
// create a tcp socket
// Options :
// AF_INET : The Internet Protocol version 4 (IPv4) address family.
// AF_INET6 : The Internet Protocol version 6 (IPv6) address family.
// SOCK_STREAM : A socket type that provides sequenced, reliable, two-way,
// connection-based byte streams with an OOB data transmission
// mechanism. This socket type uses the Transmission Control Protocol (TCP)
// for the Internet address family (AF_INET or AF_INET6).
// SOCK_DGRAM : A socket type that supports datagrams, which are connectionless,
// unreliable buffers of a fixed (typically small) maximum length. This
// socket type uses the User Datagram Protocol (UDP) for the Internet address
// family (AF_INET or AF_INET6).
// IPPROTO_TCP : The Transmission Control Protocol (TCP). This is a possible value when the af parameter is AF_INET or AF_INET6 and the type parameter is SOCK_STREAM.
// IPPROTO_UDP : The User Datagram Protocol (UDP). This is a possible value when the af parameter is AF_INET or AF_INET6 and the type parameter is SOCK_DGRAM.
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sockfd == INVALID_SOCKET)
{
printf("ERROR opening socket:%d", WSAGetLastError());
exit(-1);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
//portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
ret = bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
if (ret == SOCKET_ERROR)
{
printf("ERROR bind() error:%d", WSAGetLastError());
exit(-1);
}
ret = listen(sockfd,5);
if(ret == SOCKET_ERROR)
{
printf("ERROR on listen() error:%d", WSAGetLastError());
exit(-1);
}
clilen = sizeof(cli_addr);
do
{
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr,&clilen);
if(newsockfd == INVALID_SOCKET)
{
printf("ERROR on accept() error:%d", WSAGetLastError());
exit(-1);
}
printf("Got a connection\n");
CreateThread (
0, // Security attributes
0, // Stack size
(LPTHREAD_START_ROUTINE) &client_thread,
(LPVOID) newsockfd,
0,
&ThreadId);
}
while(1);
}
//=======================================================================
// Function : main entry point
// in : port number for the server to listen on
// return : int
// Description: to invoke, c:\server 8808 -> This will make the server listen on port 8808
//
//
int main(int argc, char *argv[])
{
//int ret;
//int sockfd, newsockfd, portno, clilen;
//struct sockaddr_in serv_addr, cli_addr;
DWORD ThreadId;
WORD wVersionRequested;
WSADATA wsaData;
int err;
if (argc < 2)
{
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
CreateThread (
0, // Security attributes
0, // Stack size
(LPTHREAD_START_ROUTINE) &discovery_response_thread,
(LPVOID) NULL,
0,
&ThreadId);
CreateThread (
0, // Security attributes
0, // Stack size
(LPTHREAD_START_ROUTINE) &broadcast_thread,
(LPVOID) NULL,
0,
&ThreadId);
CreateThread (
0, // Security attributes
0, // Stack size
(LPTHREAD_START_ROUTINE) &server_thread,
(LPVOID) NULL,
0,
&ThreadId);
Sleep(10000000); // TO DO: add code to interact with user later
}