Thursday, June 5, 2014

Playing with the sockets !


We shall look into another way of achieving IPC (inter process communication)
, which is socket communication . I have used the client server model to demonstrate the socket communication.

Important things to consider in the socket communication .

1. Port Number associated with the socket .
2. Address family i.e IPv4 or IPv6
2. How many Clients can the server accepts ?
3. Different ways of connecting the socket from the same machine(node) or different machine.



Server.c

#include<stdio.h>
#include<sys/socket.h>
#include<sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include<string.h>

#define PORT_NUM 5000

void main()
{
  int sock_fd;
  int connection_fd;
  struct sockaddr_in serv_addr;
  char buffer_to_send[32];
  /*AF_INET  - Internet IP Protocol *
   *SOCK_STREAM - stream socket
   * protocol - 0- un specified .. by default we give this option for now !! */

  sock_fd = socket(AF_INET,SOCK_STREAM,0) ;

  if(sock_fd <0)
   {
    printf("Cannot create socket \n");
    return ;
   }

  /*Address family INET i.e. ipv4
   *source address any address
   *Port specified by the PORT_NUM */

  serv_addr.sin_family = AF_INET;

  /* This INADDR_ANY allowed our program to work without knowing the IP address
   * of the machine it is being run */
  serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

  /*htons is required here to convert into the network byte order*/
  serv_addr.sin_port = htons(PORT_NUM);

  /*Tricky part here ... we are updating the serv_addr and converting the same into
   *sockadd type .. both are same but different way of representing the data
   * bind call expects it to be in the later form*/
  bind(sock_fd, (struct sockaddr*)&serv_addr,sizeof(serv_addr));


  if ( listen(sock_fd,1) == -1)
   {
    printf("Cannot listen on the socket \n");
    return ;
   }


  while(1)
    {

      /*Accept is used for establishing the connection with the client node when it tries to request for
       * the connection , we can correlate the same to 3 way TCP handshake
       * Second argument structure is filled in with the address of the peer socke we can ignore that by passing NULL
       * in that case third which is the length of the data for second argument can also be NULL*/

      connection_fd = accept(sock_fd, (struct sockaddr*)NULL ,NULL);

      strcpy(buffer_to_send, "Message from server");
      write(connection_fd, buffer_to_send, strlen(buffer_to_send));

      /*Upon successfull xmission of a msg close the socket , when the client requests for one more session
       *It will unblock from the accept call and proceeds further for seding the data  */
      close(connection_fd);
      sleep(1);
   }


}


Client.c


#include<stdio.h>
#include<sys/socket.h>
#include<sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include<string.h>
#include<errno.h>

#define PORT_NUM 5000

void main(int argc, char *argv[])
{
  int sock_fd;
  int connection_fd;
  int num_bytes;
  struct sockaddr_in client_addr;
  char recv_buffer[32];
  int ret;
  /*AF_INET  - Internet IP Protocol *
   *SOCK_STREAM - stream socket
   * protocol - PF_UNIX - used for internal communication */

  sock_fd = socket(AF_INET,SOCK_STREAM,0) ;

  if(argc != 2)
  {
      printf("\n Usage: %s <server_ip> \n",argv[0]);
      return ;
  }

  if(sock_fd <0)
   {
    printf("Cannot create socket \n");
    return ;
   }

  /*Address family INET i.e. ipv4
   *source address any address
   *Port specified by the PORT_NUM */

  client_addr.sin_family = AF_INET;


   if(inet_pton(AF_INET, argv[1], &client_addr.sin_addr)<=0)
    {
        printf("\n inet_pton error occured\n");
        return ;
    }

  /*htons is required here to convert into the network byte order*/
  client_addr.sin_port = htons(PORT_NUM);

  /*Tricky part here ... we are updating the client_addr and converting the same into
   *sockadd type .. both are same but different way of representing the data
   * bind call expects it to be in the later form*/
  ret = connect(sock_fd, (struct sockaddr*)&client_addr,sizeof(client_addr));
  //if(connect(sock_fd, (struct sockaddr*)&client_addr,sizeof(client_addr)) < 0)
  if(ret<0)
   {
     printf("Connection failed error = %s\n" , strerror(errno));
     return ;
   }


  while((num_bytes = read(sock_fd, recv_buffer, sizeof(recv_buffer)-1)) > 0)
    {
      recv_buffer[num_bytes] = 0;
      if(fputs(recv_buffer, stdout) == EOF)
       {
         printf("\n Error : Fputs error");
       }
      printf("\n");
    }

}





Output :

Here i am running server in one machine and trying to connect from two different machines ( 2 clients ) , If you look at the code i am listening for only one connection for that socket ... listen system call in the server

One can play with the number of clients options and see how it behaves differently !


# ./socket_client 127.0.0.1
Message from server

# ./socket_client 10.10.27.203
Connection failed error = Connection refused

To verify if the socket really is in listen state , we can check for the netstat o/p as follows

#netstat -ntlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name
tcp        0      0 0.0.0.0:5000                0.0.0.0:*                   LISTEN      437/./socket_server




Tuesday, June 3, 2014

Pipes & pipes !!






All these days i was thinking , why a child process needs to get all the file descriptor of the parent process. Here i see one advantage of sharing the same . i have created a pipe and then forked a child process . So child process gets all the file descriptors(fd) that were part of parent process. Ok , Here comes the interesting part !! One process closes the read end of the pipe and other process closes write end of the pipe .. So what happens ??? we get a tunnel, one process reads and other process writes ... very good ! we have achieved inter process communication with the help of this ... I have tried to write simple C program to demonstrate the same . ####
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

void main()
{
  int pipe_fd[2];
  int fd ,bytes;
  char name[32]= "I am the blogger !! \n";
  char buf[100];
memset(buf,0,sizeof(buf));
  pipe(pipe_fd);

  fd =fork();

  if(fd == 0)
  {
/*child process , close read end*/
  // while(1)
 {
    printf("Iam in child process \n");
    close(pipe_fd[0] );
    write(pipe_fd[1],name,strlen(name+1));
}
  }
  else
  {
/* Parent process , close write end*/
//while(1)
{
    printf("Iam in parent process \n");
    close(pipe_fd[1] );
    bytes = read(pipe_fd[0],buf,sizeof(buf));
    printf("bytes = %d , buf = %s \n", bytes,buf);
}
  }
Output !! # ./pipetest Iam in parent process Iam in child process bytes = 20 , buf = I am the blogger !!

Playing with FIFOs

A named pipe (also known as a FIFO for its behavior) is an extension to the traditional pipe concept on Unix and Unix-like systems, and is one of the methods of inter-process communication (IPC)

Instead of a conventional, unnamed, shell pipeline, a named pipeline makes use of the filesystem .

In this example i have used "mknod" , for creating the file and two separate processes (fifo_server & fifo_client ) can access the pipe by name — one process can open it as a reader, and the other as a writer.

############ Server ##############


#include<stdio.h>
#include<stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>

#define FIFO_FILE "my_file.txt"

void main()
{
FILE *fp ;
char read_buffer[100];

 umask(0);

/*mknod - create a special or ordinary file
 * The file type must be one of S_IFREG, S_IFCHR, S_IFBLK, S_IFIFO, or
 * S_IFSOCK to specify a regular file */

 mknod(FIFO_FILE,S_IFIFO|0777,0);

 while(1)
  {
   fp=fopen(FIFO_FILE,"r");
   fgets(read_buffer,sizeof(read_buffer),fp);
   printf("received value is %s \n",read_buffer);
   fclose(fp);
  }
}

############### Client ##################

#include<stdio.h>
#include<stdlib.h>
#define FIFO_FILE "my_file.txt"

void main()
{
FILE *fp ;
char write_buffer[100] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";


 while(1)
  {
   fp=fopen(FIFO_FILE,"w");
   fputs(write_buffer,fp);
   fclose(fp);
  }
}


Output ..

At the server side we see the data coming in from the FIFO !! Simple isn't it ??

received value is ABCDEFGHIJKLMNOPQRSTUVWXYZ
received value is ABCDEFGHIJKLMNOPQRSTUVWXYZ
received value is ABCDEFGHIJKLMNOPQRSTUVWXYZ
received value is ABCDEFGHIJKLMNOPQRSTUVWXYZ
received value is ABCDEFGHIJKLMNOPQRSTUVWXYZ


--Cheers !!