Professional Documents
Culture Documents
Google+
14-18 minutes
Communication over sockets involves 2 programs running on the same machine or on separate
machines across a network. First is a socket server and the other is a socket client. Tcp stands for
Transmission control protocol and it is the most common protocol being used for most of the
network communication that takes place over internet or a lan. There are other important
protocols like udp, arp, icmp and they are used mandatorily but in small quantities.
These protocols are technically speaking, define the format how data should be structured into
packets when sending them across a network. So every protocol has a different format and most
importantly has a different purpose. For example for all kinds of content download and upload,
tcp is used. For network analysis the icmp and arp protocols are used and so on. Every protocol
has been designed to serve a different purpose.
So in this post we shall see how to write a socket server on windows using the winsock api.
Winsock is the socket api on windows and can be used to write socket speaking applications.
The code shall be in C.
So a socket server is an application that runs on a machine and expects clients to connect to it so
that it can serve them. The steps to write a socket server are simple.
1. Create a socket.
2. Bind it to an ip and port.
3. Start listening on it
4. Accept incoming connections and process them.
Each of the above steps has an associated function as we shall soon see in the code.
/*
Bind socket to port 8888 on localhost
*/
#include<io.h>
#include<stdio.h>
#include<winsock2.h>
printf("Initialised.\n");
//Create a socket
if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
printf("Could not create socket : %d" , WSAGetLastError());
}
printf("Socket created.\n");
//Bind
if( bind(s ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR)
{
printf("Bind failed with error code : %d" , WSAGetLastError());
}
puts("Bind done");
c = sizeof(struct sockaddr_in);
new_socket = accept(s , (struct sockaddr *)&client, &c);
if (new_socket == INVALID_SOCKET)
{
printf("accept failed with error code : %d" , WSAGetLastError());
}
puts("Connection accepted");
//Reply to client
message = "Hello Client , I have received your connection. But I have to
go now, bye\n";
send(new_socket , message , strlen(message) , 0);
getchar();
closesocket(s);
WSACleanup();
return 0;
}
The above code will start a socket server on port 8888. Run it from one console and then in
another console connect to it using the telnet command. The output of the telnet should look like
this
Hello Client , I have received your connection. But I have to go now, bye
The server sends this message to the connected client. The server is built using the following
important functions
The accept function returns a new socket which indicates the connection between this program
and the remote client program. The master socket can continue to receive the next connections.
The above program demonstrates how a socket program can work, but it is very limited in its
functionality. It can just accept 1 incoming connection and after that it is dead.
For this server to be any useful, it must be able to accept multiple incoming connections and
keep processing them till the clients want. So the next attempt shall be to write a server that can
handle multiple connections and tackle all of them simultaneously.
There are many ways to handle multiple client connections. The first and most intuitive one is
using threads. As soon as a client connects, assign a separate thread to process each client.
However threads are too much work and difficult to code properly.
There are other techniques like polling. Polling involves monitoring multiple sockets to see if
"something" happened on any of them. For example, the server could be monitoring the sockets
of 5 connected clients, and as soon as any of them send a message, the server gets notified of the
event and then processes it. In this way it can handle multiple sockets. The winsock api provides
a function called "select" which can monitor multiple sockets for some activity.
Since we are able to handle all sockets together at once it is called asynchronous socket
programming. It is also called event-driven socket programming or select()-based
multiplexing.
Now after a select function returns, it re-fills the same readfds array with the readable sockets.
Same with writefds and exceptfds. This means that we have to keep calling select function in a
loop, and everytime have to prepare our list of readfds, writefds and exceptfds array of sockets to
pass.
The socket arrays are variables of type fd_set. fd_set is basically a structure that looks like this
Now that is a lot of theory. Lets get to the final code that uses all that theory to get something
working.
/*
TCP Echo server example in winsock
Live Server on port 8888
*/
#include<stdio.h>
#include<winsock2.h>
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf("Failed. Error Code : %d",WSAGetLastError());
exit(EXIT_FAILURE);
}
printf("Initialised.\n");
//Create a socket
if((master = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
printf("Could not create socket : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
}
printf("Socket created.\n");
//Bind
if( bind(master ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR)
{
printf("Bind failed with error code : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
}
puts("Bind done");
while(TRUE)
{
//clear the socket fd set
FD_ZERO(&readfds);
//wait for an activity on any of the sockets, timeout is NULL , so wait indefinitely
activity = select( 0 , &readfds , NULL , NULL , NULL);
if ( activity == SOCKET_ERROR )
{
printf("select call failed with error code : %d" , WSAGetLastError());
exit(EXIT_FAILURE);
}
//If something happened on the master socket , then its an incoming connection
if (FD_ISSET(master , &readfds))
{
if ((new_socket = accept(master , (struct sockaddr *)&address, (int *)&addrlen))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}
closesocket(s);
WSACleanup();
return 0;
}
Does that look like a big program. Compile and run it. It should show an output like this
Initialising Winsock...Initialised.
Socket created.
Bind done
Waiting for incoming connections...
Now the socket server is ready and waiting for incoming connection. At this point we need to
connect to it using some client like telnet. But wait, we are not going to use telnet. Telnet has a
problem that it always operates in character mode and that will screw up our interaction with this
simple program. So get another utility called putty or ncat. Ncat is the netcat version that comes
with nmap. Download it from their website. Or download puttytel , the putty telnet.
If you are using ncat then connect to the socket server like this
If you are using puttytel, the launch it and go to Connection > Telnet and select Passive mode.
This will make putty line mode. Then come back to Session tab and enter the hostname and port
and click open. it will connect to the server and start a black telnet like terminal.
Once the client program is connected with the server, try sending some message by typing first
and then hit enter. The server will reply back with the same message.
Initialising Winsock...Initialised.
Socket created.
Bind done
Waiting for incoming connections...
New connection , socket fd is 3972 , ip is : 127.0.0.1 , port : 1129
Welcome message sent successfully
Adding to list of sockets at index 0
127.0.0.1:1129 - hello
127.0.0.1:1129 - i am fine
And now, try to open multiple client terminals and connect at the same time to server. The server
would be able to process requests from all the clients together.
Initialising Winsock...Initialised.
Socket created.
Bind done
Waiting for incoming connections...
New connection , socket fd is 3972 , ip is : 127.0.0.1 , port : 1129
Welcome message sent successfully
Adding to list of sockets at index 0
127.0.0.1:1129 - hello
127.0.0.1:1129 - i am fine
127.0.0.1:1131 - ha ha ha
Now thats a long run. I will go and take a cup of coffee, and meanwhile you check if the
programs are running fine.
/*
Bind socket to port 8888 on localhost
*/
#include<io.h>
#include<stdio.h>
#include<winsock2.h>
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf("Failed. Error Code : %d",WSAGetLastError());
return 1;
}
printf("Initialised.\n");
//Create a socket
if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
printf("Could not create socket : %d" , WSAGetLastError());
}
printf("Socket created.\n");
//Bind
if( bind(s ,(struct sockaddr *)&server , sizeof(server)) == SOCKET_ERROR)
{
printf("Bind failed with error code : %d" , WSAGetLastError());
}
puts("Bind done");
c = sizeof(struct sockaddr_in);
new_socket = accept(s , (struct sockaddr *)&client, &c);
if (new_socket == INVALID_SOCKET)
{
printf("accept failed with error code : %d" , WSAGetLastError());
}
puts("Connection accepted");
//Reply to client
message = "Hello Client , I have received your connection. But I have to
go now, bye\n";
send(new_socket , message , strlen(message) , 0);
getchar();
closesocket(s);
WSACleanup();
return 0;
}