PoiNtEr->: Socket Programming - Handling Connections

                             Difference between a dream and an aim. A dream requires soundless sleep, whereas an aim requires sleepless efforts.

Search This Blog

Saturday, July 21, 2012

Socket Programming - Handling Connections


Continuing from my Last Post -Socket Programming in C
To handle every connection we need a separate handling code to run along with the main server accepting connections.
One way to achieve this is using threads. The main server program accepts a connection and creates a new thread to handle communication for the connection, and then the server goes back to accept more connections.
                                       
On Linux threading can be done with the pthread (posix threads) library.
We shall now use threads to create handlers for each connection the server accepts. Lets do it man.


#include<stdio.h>
#include<string.h> //strlen
#include<stdlib.h> //strlen
#include<sys/socket.h>
#include<arpa/inet.h> //inet_addr
#include<unistd.h> //write

#include<pthread.h> //for threading , link with lpthread

void *connection_handler(void *);

int main(int argc , char *argv[])
{
int socket_desc , new_socket , c , *new_sock;
struct sockaddr_in server , client;
char *message;

//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}

//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8881 );

//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
puts("bind failed");
return 1;
}
puts("bind done");

//Listen
listen(socket_desc , 3);

//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
while( (new_socket = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) )
{
puts("Connection accepted");

//Reply to the client
message = "Hello Client , I have received your connection. And now I will assign a handler for you\n";
write(new_socket , message , strlen(message));

pthread_t sniffer_thread;
new_sock = malloc(1);
*new_sock = new_socket;

if( pthread_create( &sniffer_thread , NULL ,  connection_handler , (void*) new_sock) < 0)
{
perror("could not create thread");
return 1;
}

//Now join the thread , so that we dont terminate before the thread
//pthread_join( sniffer_thread , NULL);
puts("Handler assigned");
}

if (new_socket<0)
{
perror("accept failed");
return 1;
}

return 0;
}

//This will handle connection for each client
void *connection_handler(void *socket_desc)
{
//Get the socket descriptor
int sock = *(int*)socket_desc;

char *message;

//Send some messages to the client
message = "Greetings! I am your connection handler\n";
write(sock , message , strlen(message));

message = "Its my duty to communicate with you";
write(sock , message , strlen(message));

//Free the socket pointer
free(socket_desc);

return 0;
}

Run the above server in one terminal and use other to communicate with server. Now the server will create a thread for each client connecting to it.

The telnet terminals would show :

$ telnet localhost 8881
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hello Client , I have received your connection. And now I will assign a handler for you
Hello I am your connection handler
Its my duty to communicate with you

This one looks good , but the communication handler is also quite dumb. After the greeting it terminates. It should stay alive and keep communicating with the client.

One way to do this is by making the connection handler wait for some message from a client as long as the client is connected. If the client disconnects , the connection handler ends.

So the connection handler can be rewritten like this :


/* This will handle connection for each client

void *connection_handler(void *socket_desc)
{
//Get the socket descriptor
int sock = *(int*)socket_desc;
int read_size;
char *message , client_message[2000];

//Send some messages to the client
message = "Greetings! I am your connection handler\n";
write(sock , message , strlen(message));

message = "Now type something and i shall repeat what you type \n";
write(sock , message , strlen(message));

//Receive a message from client
while( (read_size = recv(sock , client_message , 2000 , 0)) > 0 )
{
//Send the message back to client
write(sock , client_message , strlen(client_message));
}

if(read_size == 0)
{
puts("Client disconnected");
fflush(stdout);
}
else if(read_size == -1)
{
perror("recv failed");
}

//Free the socket pointer
free(socket_desc);

return 0;
}

The above connection handler takes some input from the client and replies back with the same. Simple! Here is how the telnet output might look

$ telnet localhost 8881
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hello Client , I have received your connection. And now I will assign a handler for you
Greetings! I am your connection handler
Now type something and i shall repeat what you type
Hello
Hello
hi
hi
hehe
hehe
So now we have a server thats communicative. Thats useful now.
When compiling programs that use the pthread library you need to link the library. This is done like this
gcc program.c -lpthread

No comments:

Post a Comment