Network Programming in GNU/LINUX:Importance of socket ports and Difference in coding of TCP and UDP socket applications

TCP and UDP are both transport layer protocols which involves process to process communication .As it is very important to identify the recipient device Locally or over Internet since

there will more than one computer in the network , it is equally important to identify right process in the receivers computer to which information has to be send since there will hundreds of processes running.

We’ll consider a practical scenario , Let us assume that users on system1 and system2 are communicating over INTERNET using 2 different programs , a Chat application and a VOIP based Application like SKYPE. The data sent from the Chat Application process from the system1 has to reach the chat application process running the system2 , not to any other process and it should follow he same in case of the VOIP application .The concept of software or logical ports help us identify the right process to receive the information across the network once the device is identified using its Network layer address(IP address) or data link layer address(MAC address).

 The concept of a network capable application or a process running on logical port ensures that the communication takes place between intended processes at the transport layer .

 TCP is connection oriented with many more checking mechanisms used to ensure message delivery and completeness , UDP has minimal checking, does not maintain a connection or ensure completeness or delivery of message.

TCP(Transmission Control Protocol). TCP is a connection-oriented protocol, a connection can be made from client to server, and from then on any data can be sent along that connection.

    • Reliable – when you send a message along a TCP socket, you know it will get there unless the connection fails completely. If it gets lost along the way, the server will re-request the lost part. This means complete integrity, things don’t get corrupted.

    • Ordered – if you send two messages along a connection, one after the other, you know the first message will get there first. You don’t have to worry about data arriving in the wrong order.

    • Heavyweight – when the low level parts of the TCP “stream” arrive in the wrong order, resend requests have to be sent, and all the out of sequence parts have to be put back together, so requires a bit of work to piece together.

  1. UDP(User Datagram Protocol). A simpler message-based connectionless protocol. With UDP you send messages(packets) across the network in chunks.

    • Unreliable – When you send a message, you don’t know if it’ll get there, it could get lost on the way.

    • Not ordered – If you send two messages out, you don’t know what order they’ll arrive in.

    • Lightweight – No ordering of messages, no tracking connections, etc. It’s just fire and forget! This means it’s a lot quicker, and the network card / OS have to do very little work to translate the data back from the packets.

 

While writing TCP based socket applications the connection has to be first established b/w the two process in the sender and reciever devices before any exchange of information could take place .the sequence of system calls involved in creating a TCP client/server program are as follows .

 Image

The connect call from the client establishes the connection b/w client and the server only after which the information exchange takes place .The following figure shows the sequence of calls involved in creating a TCP based Client/server application.

The following figure shows shows the sequence of calls involved in creating UDP based client/server application

 Image

 

Advertisements

Network Programming in GNU/LINUX- socket() system call

Image

The elementary system call in an any SOCKET/NETWORK program(server/client) in GNU/LINUX written using C is socket().The call to socket() creates a socket ,that is a communication end point.The prototype for the socket call is as follows

#include <sys/socket.h>

int socket(int domain, int type, int protocol);

The domain(first argument) can be one of the following values .It specifies the address family(AF)

     Name                   Purpose                 
       AF_UNIX, AF_LOCAL      Local communication              
       AF_INET                IPv4 Internet protocols        
       AF_INET6               IPv6 Internet protocols
       AF_IPX                 IPX - Novell protocols
       AF_NETLINK             Kernel user interface device    
       AF_X25                 ITU-T X.25 / ISO-8208 protocol 
       AF_AX25                Amateur radio AX.25 protocol
       AF_ATMPVC              Access to raw ATM PVCs
       AF_APPLETALK           Appletalk                      
       AF_PACKET              Low level packet interface 

  The socket has the indicated type(second argument), which specifies the communication semantics. Currently defined types are:

Tag

Description

SOCK_STREAM

 

Provides sequenced, reliable, two-way, connection-based byte streams. An out-of-band data transmission mechanism may be supported.

SOCK_DGRAM

 

Supports datagrams (connectionless, unreliable messages of a fixed maximum length).

SOCK_SEQPACKET

 

Provides a sequenced, reliable, two-way connection-based data transmission path for datagrams of fixed maximum length; a consumer is required to read an entire packet with each read system call.

SOCK_RAW

 

Provides raw network protocol access.

SOCK_RDM

 

Provides a reliable datagram layer that does not guarantee ordering.

SOCK_PACKET

 

Obsolete and should not be used in new programs

CAUTION:All combinations of domain(first argument) and type(second argument) are not valid.

The third argument protocol  specifies  a  particular  protocol  to  be used with the    socket.  Normally only a single protocol exists to support a particular  socket  type within a given protocol family, in which case protocol can  be specified as 0.

RETURN VALUE
       On  success,  a  file  descriptor  for  the new socket is returned.  On
       error, -1 is returned, and errno is set appropriately.

ERRORS
       EACCES Permission to create a socket of the specified type and/or  protocol is denied.

       EAFNOSUPPORT
        The  implementation  does not support the specified address family.

       EINVAL

       Unknown protocol, or protocol family not available.

       EINVAL

       Invalid flags in type.

       EMFILE

       Process file table overflow.

       ENFILE

       The system limit on the total number  of  open  files  has  been  reached.

       ENOBUFS or ENOMEM
              Insufficient  memory is available.  The socket cannot be created
              until sufficient resources are freed.

       EPROTONOSUPPORT
              The protocol type or the specified  protocol  is  not  supported  within this domain.

Network Programming in GNU/LINUX:Introduction on building a server application in GNU/LINUX using C socket API’s

/*This is an Introduction on building a server application in GNU/LINUX using C socket API’s*/
/*Run this program and issue “netstat -ant | grep 7004” in another terminal, you can see the server listening */

/*accept system call doesnot return till either it encounters an error or gets a connection from a client(such system calls are called as blocking system call */
#include<sys/socket.h>
#include<netinet/in.h>
int main()
{
    int sd,len;
    struct sockaddr_in servaddr,cliaddr;//socket structure
    sd=socket(AF_INET,SOCK_STREAM,0);/*elementary call in any client server application to create an socket*/

    bzero(&servaddr,sizeof(servaddr));//to initialize all elements of the structure to zero
    servaddr.sin_addr.s_addr=htonl(INADDR_ANY);//To assian a arbitrary IP to the server
    servaddr.sin_family=AF_INET;
    servaddr.sin_port=htons(7004);//port on which the server listens
    bind(sd,(struct sockaddr *)&servaddr,sizeof(servaddr));/*assign the IP and port information to the socket */
    listen(sd,5);/*Listen for incoming coonections */
    len=sizeof(cliaddr);
    accept(sd,(struct sockaddr *)&cliaddr,&len);/*accept the incoming connections*/
    return 0;
}

Race conditions in fork system call , difference b/w fork and vfork system calls in GNU/LINUX

We say that the RACE conditions conditions exist in a program if the sequence in which the output is produced is unpredictable because of the order in which the programs are executed . After forking(executing fork system call), if the child and parent process have sequence of instructions to perform , the execution control will be toggling b/w Child and parent due the internal scheduling algorithm of the kernel , and the order of execution of the instruction is unpredictable .The following code illustrates this concept .

Image

#include<unistd.h>
#include<stdlib.h>
int main()
{
    int i,j;
    i=fork();
    if(i==0)//child process
    {
        for(j=1;j<=10;j++)
         printf(“\nChild here\n”);
        exit(0);
    }
    else //parent process
    {
        for(j=1;j<=10;j++)
         printf(“\nParent here\n”);

    }
   exit(0);
}
As you can clearly see the output is intermixed because of the switch in control of execution b/w child and the parent process .This is unavoidable .The possible solutions be either to make the parent sleep this the child completes execution or use vfork() system call

vfork() works similar to fork(), but vfork() doesnt begin the execution the of the parent process till either the child execs(executes any of the exec() family of calls) or the child exits.Unlike fork() the child process from vfork() doesnt copy the address space of the parent .It is usually used when the child process is created with a purpose of executing the exec() system call.Since vfork() system call doesnt start the execution of parent process and waits till the child execs or exits ,thus race condition is avoided.The sample code below illustrates this concept.

Image

 

#include<unistd.h>
#include<stdlib.h>
int main()
{
    int i,j;
    i=vfork();
    if(i==0)//child process
    {
        for(j=1;j<=10;j++)
         printf(“\nChild here”);
        exit(0);
    }
    else //parent process
    {
        for(j=1;j<=10;j++)
         printf(“\nParent here”);

    }
   exit(0);
}
This program is similar to the earlier one ,but instead of fork(), vfork() is used .You can clearly see that the output is not intermixed as in case of fork() , since vfork() doesnt start the execution of the parent till the child finishes executing the instructions it execs or exits.

 

Program to show that the child process gets a copy of Data , Heap and Stack Segments from the parent process across a fork call in GNU/LINUX

Local Variables are stored in Stack. Register variables are stored in Register. Global variables,  static variables and extern variables are stored in data segment. The memory created dynamically are stored in Heap And the C program instructions get stored in code segment(text segment).

When fork() is invoked the child process gets a copy of parent’s heap,stack and data segment.but the text segment is shared.Here is a simple program to illustrate this.It can be clearly seen in the output that the values are modified just in the child process since it has its own data,heap and stack segments which was copied from the parent across fork() call.

#include<unistd.h>
#include <stdlib.h>
int global=10; //global variable stored in data segment ;
int main()
{
    int stack=10,i; //local variable , stored in stack segment ;
    char *buf;
    buf=(char *)malloc(20);//dynamically allocated variable, stored in heap;
    buf="PARENT";
    i=fork();
    if(i==0)//child process
    {
        global=20;
        stack=20;
        buf="CHILD";
    }
    printf("\n stack=%d,global=%d,buf=%s\n ",stack,global,buf);
    return 0;
}

Image

Singals in GNU/LINUX .SIGCONT , SIGTTIN and SIGTTOU

Its not possible for a background process to read from the standard input .You can try this by issuing the following command “cat > test.txt & ” , then hit enter Twice .The process will be suspended as the signal ‘SIGTTIN’ will be generated , and the process will be suspended.But a background process can write into standard output .But this feature can be disabled by using “stty tostop” command from the terminal.Under this circumstance when stty is set a background process which tries to write into the standard output will be sent “SIGTTOU” signal and the process will be suspended . To continue the process which were suspended by them SIGCONT signal  has to be sent to them .Image

Program in GNU/LINUx to find the termination status of child process using wait system call and WIFEXITED and WIFSIGNLED MACROS

Image

/*download link for the program:http://www.slideshare.net/hackintoshrao/childexittest*/
/* The wait systems waits for the Child process to exit  if the child process is still under exection and
   wait call returns with the process ID of the exited child process and it stores the childs
   exit status in the argument passed to it

   pid_t wait(int *status);

   But there are 2 different ways by which a child process can exit
    1)  Normal Termination
       -This happens when the child process calls exit() or return
    2)  Abnormal termination
       -this happens when the child process is terminated by by an SIGNAL
          *when child calls abort system call , it will be killed ny ABORT signal no 6
          *when child tries to divide a number by 0 , it will be killed by signal no 8
    but the status obtained by the waitpid system call doesnt give an idea about whether the
    child process terminated normally or abnormally
    to find it out we can use these 2 macros defined in <sys/wait.h> and stdlib.h>
     -if the process has terminated nomrally we can find out the exit status ising these macros
     -if the process had terminated abnormally by an Signal then we can find out the Signal
      number of the signal which killed the child process

      the status obtained by wait system call has to be passed as an argement to these macros
      these macros are

      1)WIFEXITED(status)
Description:
 Returns True if status was returned for a child that terminated normally. In this case, we can
 execute WEXITSTATUS(status) to fetch the value that the child passed to exit, _exit,or _Exit.

      2)WIFSIGNALED(status)
 Returns True if status was returned for a child that terminated abnormally, by receipt of a signal
 that it didn’t catch. In this case, we can execute WTERMSIG(status)

*/
#define err_sys(msg) write(1,msg,50)
#include <stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include <sys/wait.h>
#include<sys/types.h>

void Info_on_termination_of_child(int status)
{
if (WIFEXITED(status))
 printf(“normal termination, exit status = %d\n”,WEXITSTATUS(status));

else if (WIFSIGNALED(status))

   printf(“abnormal termination, signal number = %d\n”,WTERMSIG(status));

}

int main(void)
{
pid_t pid;
int status;

if ((pid = fork()) < 0)//creating a child
 err_sys(“fork error”);
else if (pid == 0) /* child process*/
 exit(7); /*child process exiting normally ,only parent left*/
if (wait(&status) != pid) /*parent waiting for child */
 err_sys(“wait error”);
Info_on_termination_of_child(status);/*calling the function to get termination info*/

if ((pid = fork()) < 0)//forking to create a child again
 err_sys(“fork error”);
else if (pid == 0)/*child proces*/
 abort();/*Abnormal termintionof child process by ABORT signal only parent left*/
if (wait(&status) != pid)/*parent waiting for child to exit*/
err_sys(“wait error”);
Info_on_termination_of_child(status);/*calling the function to get termination info*/

if ((pid = fork()) < 0)
err_sys(“fork error”);
else if (pid == 0)
status =(status/0);
/* Division by Zero error generates SIGNAL.NO 8 which kills the child,only parent left*/
if (wait(&status) != pid) /*parent waiting for child process to end*/
 err_sys(“wait error”);
Info_on_termination_of_child(status);

exit(0);
}