Analysing the Stream Socket connection

In the current article, we try and analyze what occurs at each stage of the Stream socket connection example. 

The Stream Socket example code for IPv4 is provided at this link here. The interested reader can look at the code on his linux shell and try and follow the actual connection establishment here. 

The initial code to create a socket on the server or the client is provided below

         /* Part 1 – create a socket */
         /* create the socket FD */
         socket_fd = socket(AF_INET, SOCK_STREAM, 0);

         if (socket_fd < 0) {
                 printf(“The Socket API call failed\n”);
                 exit(0);
         }

If the above call to “socket API” succeeds, then a socket File Descriptor is provided to the application invoking the socket call. The socket is currently not bound to any address. The “Bind API” will bind the socket to an address at the server side. The code for bind is shown below

          serveraddr->sin_addr.s_addr = inet_addr(“127.0.0.1”);
          serveraddr->sin_port = htons(PORT);

          /* Part 3 – bind and start accepting connections */

          if(0 != bind(socket_fd, (struct sockaddr *)serveraddr, sizeof(struct                                                                       sockaddr_in))) {
                     printf(“unable to bind to the socket\n”);
                     goto end1;
          }

          /* accept up-to 5 pending requests
           * and make the server socket a passive socket to accept clients           
           */ 
          if (listen(socket_fd, 5) == -1) {
                   printf(“Listen Failed\n”);
                  goto end1;
        }

When Bind API succeeds, the socket File descriptor will be bound to  a Port and IP address. The socket is placed in listen state to accept client connections. The output of the “ss shell command” after the successful invocation of listen shows the current state of the bound socket to be in listen state. The socket state is marked in Red. It can be seen that the socket is in listen state and bound to 127.0.0.1:55000 and does not have a peer connection yet

State         Recv-Q Send-Q Local Address:Port                    Peer Address:Port
LISTEN         0        128          127.0.0.53%lo:domain              0.0.0.0:*
LISTEN         0        5               127.0.0.1:ipp                                   0.0.0.0:*
LISTEN         0        5               127.0.0.1:55000                            0.0.0.0:*
TIME-WAIT 0        0           192.168.0.6%enp0s3:51034         35.224.99.156:http
LISTEN         0        5               [::1]:ipp                                       [::]:*

After entering into listen state, the server code will await for incoming connections on an accept API call. The code for the same is provided below

    /* accept is a blocking call and the call would stop further invocation of               *  code till a client connection is accepted */
        printf(“waiting for connection\n”);
        clientfd = accept(socket_fd, (struct sockaddr *)clientaddr, &length);

        if (clientfd < 0) {
                 printf(“Unable to connect to Client FD\n”);
                 goto end2;
        }

clientfd is a socket file descriptor and is the client connection socket. Note that, accept is a blocking call and the server will wait for incoming connections at the instance of accept API invocation.

On the client side, after a socket is created, the client tries to connect to the IPaddress and port combination of the server. Notice that the client does not bind in this example case. The Kernel will provide a port number for the client socket. The code snippet achieving that operation for the client is provided below

        sockaddrin->sin_family = AF_INET;
        sockaddrin->sin_port = htons(PORT);

        sockaddrin->sin_addr.s_addr = inet_addr(“127.0.0.1”);

         /* part 3 – connect to the server defined by IP address and port*/
         /* connect to the server */
        if (0 != connect(socket_fd, (struct sockaddr *)sockaddrin,
                (socklen_t)(sizeof(struct sockaddr_in)))) {
                printf(“Unable to connect\n”);
                /* unable to connect to server */
               goto end1;
        }

if connect attempt to the server succeeds, then the socket connection is established and the socket can be used to transmit and receive data on the socket. The port number for the client is allocated by the linux kernel.

The connect API on a TCP stream socket invokes a TCP 3-way handshake. The output of the “ss shell command” after connect and the 3-way handshake is also provided below for the reader’s understanding and reference

State         Recv-Q    Send-Q Local Address:Port           Peer Address:Port
LISTEN        0             128       127.0.0.53%lo:domain     0.0.0.0:*
LISTEN        0              5           127.0.0.1:ipp                      0.0.0.0:*
LISTEN        0              5           127.0.0.1:55000                  0.0.0.0:*
ESTAB          50            0           127.0.0.1:57798                 127.0.0.1:55000
ESTAB          0              50         127.0.0.1:55000                 127.0.0.1:57798
LISTEN         0              5           [ ::1]:ipp [::]:*

The interested reader can run Wireshark on the loopback interface (since the socket is created on the lo address – 127.0.0.1) and capture the three way handshake.

A UDP Socket Connection 

Comments

  1. Pingback: A Socket Server/Client Example – TCP Stream Sockets | Hitch Hiker's Guide to Learning

Leave a Reply

Your email address will not be published. Required fields are marked *