Wednesday, 22 February 2017

Socket Programming using C


What is socket and Use of socket :


           Socket establishes communication between two process using TCP/UDP protocols. The process can be present in same computer or different computers. It is one of the inter process communication (IPC) mechanism. It follows client-server architecture. Both client and server creates socket. Client socket requests connection with server and Once the server accepts connection request , Communication establish between client and server. Then, information can exchange between client and server and after client can request server to close the connection.

Socket API :

Socket system calls are used to create sockets and establish communication between client and server.

System calls for server :

socket()
bind()
listen()
accept()
read()
write()
close()

System calls for client :

socket()
connect()
read()
write()
close()


Socket() :

Socket system call used to create a socket in both client and server side , To ensure that ready for communication. Which requires three below information,

1) Address domain :

Unix and Internet are the two widely used address domain. Unix domain used for share common file system between process. Internet domain used for two process, Which is running under two host on network. Address format of internet domain is IP address of host and also required port number on that host.
2) Socket Type :

It consists two called stream and data-gram. Stream type uses TCP protocol (reliable and stream oriented) and data-gram uses UDP (unreliable and message oriented).

3) Protocol :

It mostly specified by value 0. Which means operating system can determine proper protocol based on socket type. If it is stream then protocol will be TCP. If it is data-gram then protocol will be UDP.

Syntax : socket(addr_domain, socket_type, protocol)

Example :

int sock_id = socket(AF_INET, SOCK_STREAM, 0);

Note : On successful creation of socket , It returns socket file discriptor, It will be > 0. On failure of creation, Socket call returns -1.

Bind() :

On successful creation of socket , Server tries to binds created socket with address of host using IP and port of server host. It takes three information as arguments. Socket file descriptor, The address to which is bound, and the size of the address to which it is bound. The second argument is a pointer to a structure of type socketaddr, but what is passed in is a structure of type sockaddr_in, and so this must be cast to the correct type. Make sure that post number should not be used by any other process of host. It leads to bind failure mostly.

Syntax : bind(socket_disp address of sockaddr, sizeof sockaddr);

Example :

struct sockaddr_in
{
  short   sin_family; /* must be AF_INET */
  u_short sin_port;
  struct  in_addr sin_addr;
  char    sin_zero[8]; /* Not used, must be zero
*/
};

struct sockaddr_in ser_addr,
cli_addr;

int port_no = 5555
ser_addr.sin_family = AF_INET;
ser_addr.sin.port = htons(port_no);
ser_addr.sin_addr.s_addr = INADDR_ANY;

htons – Simply converts port number into network byte order.
INADDR_ANY – It specifies IP address of server. Instead of hard coding IP address, We can use INADDR_ANY, Which gets IP address of running host.

bind(sock_id, (struct sockaddr *)&ser_addr, sizeof(ser_addr));

Note : On failure , Bind system call returns < 0.

Listen() :

The listen system call allows the process to listen on the socket for connections. The first argument is the socket file descriptor, and the second is the size of the backlog queue, i.e., the number of connections that can be waiting while the process is handling a particular connection. This should be set to 5, the maximum size permitted by most systems. If the first argument is a valid socket, this call cannot fail, and so the code doesn't check for errors.

Syntax : listen(sock_disp, no_of_connection can wait in queue);
Example : listen(sock_id, 5);

Accept() :

The accept system call requires three information as argument. When a connection from a client has been successfully established. It returns a new file descriptor, and all communication on this connection should be done using the new file descriptor. The second argument is a reference pointer to the address of the client on the other end of the connection, and the third argument is the size of this structure. Until, Connection request from client , accept system call blocks the server.

Syntax : accept(sock_desp, addr_of client sock, size of client sock);

Example :

cli_sock_id = accept(sock_id, (struct sockaddr *) &cli_addr, sizeof(cli_addr));

Note : On failure case , Accept system call returns < 0.

Read() :

On Successful accepting client connection request, Ensuring connection has been established between both client and server process. Now , Client can request server to exchange the information. Those requests are received by read () system call. It requires three information as arguments called new socket descriptor returned by accept() system call, Buffer to store client requested information or sent information and size of the buffer.

Syntax : read(new_sock_desp, buffer, size of buffer);

Example :

char buffer[1024] = {0x00};
memset(buffer,0x00,sizeof(buffer));
// buffer may have message as “Hi server”.

int ret = read(cli_sock_id, buffer, sizeof(buffer));

Note : On successful read, returns number of character read and On failre case < 0.

Write() :

On successful connection establishment between client and server socket, Server can response to client's request using write() system call. It takes three arguments called new socket discriptor returned by accept() system call, Message to be communicate or response to client's request and size of message or response.

Syntax : write(new_sock_desp, message or response, size of msg or resp);

Example :

int resp = write(cli_sock_id, “Hello client”, 20);

Note : On failure returns < 0.


Connect() :

Connect system call used in client side to establish connection request with server. It has three arguments called sock_desp, server address(IP and Port) and size of address.

Syntax : connect(sock_desp, &server_addr, sixeof(server_addr));

Example :

struct sockaddr_in ser_addr;

int port_no = 5555
ser_addr.sin_family = AF_INET;
ser_addr.sin.port = htons(port_no);
ser_addr.sin_addr.s_addr = “10.0.0.1”;
int resp = connect(sock_id, (struct sockaddr *) &ser_addr, sizeof(ser_addr));

Note : On successful. Returns 0 and -1 for failed.


Server side program :

#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#define PORT 5555

int main(int argc, char const *argv[])
{
    int server_fd, new_socket, valread;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[1024] = {0};
    char *hello = "Hello from server";
      
    // Creating socket file descriptor
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
    {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }
      
    
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons( PORT );
    
    // bind to IP and port  
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0)
    {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
    if (listen(server_fd, 5) < 0)
    {
        perror("listen");
        exit(EXIT_FAILURE);
    }

    // Accept client connection and establish 
    if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0)
    {
        perror("accept");
        exit(EXIT_FAILURE);
    }

    // Receive client request and read the buffer
    valread = read( new_socket , buffer, sizeof(buffer));
    if(valread >= 0)
    {
    printf("%s\n",buffer );
    write(new_socket , hello , strlen(hello) , 0 );
    printf("Hello message sent\n");
    }
    else
    {
printf("Error in reading the buffer\n");
    }

    close(server_fd);
     
    return 0;
}



Client side program :

#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#define PORT 5555
  
int main(int argc, char const *argv[])
{
    struct sockaddr_in address;
    int sock = 0, valread;
    struct sockaddr_in serv_addr;
    char *hello = "Hello from client";
    char buffer[1024] = {0};
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        printf("\n Socket creation error \n");
        return -1;
    }
  
    memset(&serv_addr, '0', sizeof(serv_addr));
  
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
      
    // Convert IPv4 and IPv6 addresses from text to binary form
    if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0) 
    {
        printf("\nInvalid address/ Address not supported \n");
        return -1;
    }
  
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
    {
        printf("\nConnection Failed \n");
        return -1;
    }
    if(write(sock , hello , strlen(hello) , 0 ) < 0)
    {
  printf("Error in writing\n");
    }
    printf("Hello message sent\n");
    
   if(read( sock , buffer, sizeof(buffer)) < 0)
    {
printf("Error in reading\n");
    }
    printf("%s\n",buffer );

    close(sock);
    return 0;
}


Note : Save server and client program as separate file like server.c and client.c. Compile both separately by using below command,

gcc -o server_socket server.c

gcc -o client_socket client.c


After successful compilation , Run server_socket object in terminal and run client_socket object in new terminal.



Thank you for visiting!!