Monday, 17 June 2013

client and server interaction

Hi, welcome,

Ever wondered how does your server identify you and provide the service you request for? 

             Its very simple. In this post you will learn about a simple interaction between the client and the server.

To start off,  lets look at one of the simplest things that you can do - we will initialize a stream connection and receive a message from a remote server.

Consider the below c program - a simple code for the client .

Here socket connection is established between the client and the server and the client receives the message sent by the server, note that for demonstration purpose we use the same system as the client and the server .

Well lets start coding the client machine

Here it goes !!!

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>

 #define MAX_SIZE_OF_MESSAGE 500
#define PORT_NUMBER 2343

int main(int argc, char *argv[])
{

     1 } char buffer[MAX_SIZE_OF_MESSAGE + 1];

     2 } int len, wetechies_socket;

     3 } struct sockaddr_in destination_machine;

     4 } mysocket = socket(AF_INET, SOCK_STREAM, 0);

     5 } memset(&dest, 0, sizeof(dest));      
         
     6 } dest.sin_family = AF_INET;

     7 } destination_machine.sin_addr.s_addr = inet_addr("127.0.0.1"); 

     8 }  dest.sin_port = htons(PORTNUM);         
       
     9 } connect(wetechies_socket, (struct sockaddr *)&destination_machine, sizeof(struct sockaddr));

   10 }  len = recv(wetechies_socket, buffer, MAX_SIZE_OF_MESSAGE, 0);

   11 }   buffer[len] = '\0';

   12 } printf("Received %s (%d bytes).\n", buffer, len);

   13 }  close(wetechies_socket);

   14 } return EXIT_SUCCESS;

}

***********************************************************************************************
Explanation for the client program

Line 1 - An array by name buffer of type char is created with the size MAX_SIZE_OF_MESSAGE + 1 (+1 is used so that we can add the null terminator too).

Line 2 - Initialization of the variables len  (used to hold the length of the message received from the server (line 10) ) and mysocket .

Line 3 - Creates a variable destination_machine which is a struct of type sockaddr_in , This struct stores information about the machine we want to connect to.

Line 4 - The socket() function tells our OS that we want a file descriptor for a socket which we can use for a network stream connection; what the parameters mean is mostly irrelevant for now. But if your are interested you can always explore it by using the man page by hyst typing the command man socket.

Line 5memset() is used to zero the struct variables. you can again use the man page by typing the command man memset to know more about the memset function

Line 6 - Sets the address family. This should be the same value that was passed as the first parameter to socket(); for most purposes AF_INET will serve.

Line 7 - Here is where we set the IP address of the machine we need to connect to(here we use 127.0.0.1 which is know as the loopback address and refers to your own machine). The variable destination_machine.sin_addr.s_addr is just an integer stored in Big Endian format, but we don't have to know that as the inet_addr() function will do the conversion from string into Big Endian integer for us. 

Line 8 - This line sets the destination port number. The htons() function converts the port number into a Big Endian short integer. If your program is going to be run solely on machines which use Big Endian numbers as default then destination_machine.sin_port = 21 would work just as well. However, for portability reasons htons() should always be used. 

Line 9 - Establishes a connection with the server machine.

Line 10 - Receives up to MAX_SIZE_OF_MESSAGE bytes of data from the connection and stores them in the buffer string. The number of characters received is returned by recv()

Line 11 - The data received will not automatically be null terminated when stored in the buffer, so we need to do it ourselves with buffer[inputlen] = '\0'

*************************************************************************

Now lets start coding the server machine

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>

#define PORTNUM 2343

int main(int argc, char *argv[])
{

    char msg[] = "wetechies !\n";

    struct sockaddr_in destination_machine;

    struct sockaddr_in server;

    int wetechies_socket;          

    socklen_t socksize = sizeof(struct sockaddr_in);

    memset(&server, 0, sizeof(server));        

    server.sin_family = AF_INET;              

    server.sin_addr.s_addr = htonl(INADDR_ANY);

    server.sin_port = htons(PORTNUM);          
    wetechies_socket = socket(AF_INET, SOCK_STREAM, 0);

    bind(wetechies_socket, (struct sockaddr *)&server, sizeof(struct sockaddr));

    listen(wetechies_socket, 1);
    int connection_socket = accept(wetechies_socket, (struct sockaddr *)&destination_machine, &socksize);

    while(connection_socket)
    {
        printf("Incoming connection from %s - sending welcome\n", inet_ntoa(destination_machine.sin_addr));
        send(connection_socket, msg, strlen(msg), 0);
       connection_socket = accept(wetechies_socket, (struct sockaddr *)&destination_machine, &socksize);
    }

    close(connection_socket);
    close(wetechies_socket);
    return EXIT_SUCCESS;
}

***********************************************************************************************
Explanation for the server program

In fact, this is very similar to the client program. The main difference is that rather than creating a sockaddr_in with information about the machine we are trying to connect, we create it with information about the server, and then we bind() it to the socket. 

The listen() function then tells our program to start listening using the given socket.

The second parameter of listen() allows us to specify the maximum number of connections that can be queued.

Each time a connection is made to the server it is added to the queue.We take connections from the queue using the accept() function. The accept() function returns another socket. This socket is essentially a "session" socket, and can be used solely for communicating with connection we took off the queue. The original socket (mysocket) continues to listen on the specified port for further connections.
 ***************************************************************


Leave your doubts or suggestions in comments section...

No comments:

Post a Comment