Sushant Gaurav

TCP Server-Client Implementation

The communication between different processes on the same nodes or different nodes in a network is done using the concept of a socket. A socket is a structure that allows communication between processes (of the same or different machines) i.e. sending and receiving data over a network. A socket works with the port number associated with the processes that are involved in the communication. Now in the OSI model, we have the transmission control protocol that defines the standard of establishing and maintaining the conversation (or sockets) that will be used by the applications to exchange the data.

What is a Socket?

A computer network is a set of devices (computers) connected to exchange information and resources such as files, data, images, etc. The communication between two or more devices is the communication between the processes present on the different nodes or different computers in a network.

The communication between different processes on the same nodes or different nodes is done using the concept of a socket. A socket is an end-point structure that allows the communication between processes i.e. sending and receiving data over a network.

Refer to the image for more clarity.

tcp-ip-ports-and-sockets

In more theoretical terms, a socket can be defined as an endpoint present in a two-way communication link (present between two processes running on the network). As we know for communication first the location of the destination computing node is identified using the IP address (Internet Protocol Address) of the node’s network. After identifying the network location of the computer node, we need to identify its actual physical address which is done with the help of MAC address (Media Access Control Address). Finally, the actual communication has to be done between the processes, and the identification of the actual process is done with the help of the port address.

A socket is bound to the port number so that the process is identified. In the OSI model, the port addressing and process communication dealt with the TCP which stands for Transmission Control Protocol. The TCP is a transport layer connection-oriented protocol that defines the standard of establishing and maintaining the conversation that will be used by the applications to exchange the data.

What is TCP?

The OSI model stands for Open Systems Interconnection model. The OSI model is also known as the ISO-OSI model as it was developed by ISO (International Organization for Standardization). It is a conceptual reference model that describes the entire flow of information from one computer to the other computer. The OSI model is a 7-layered model so it is also known as a 7-layered architecture model. The basic idea behind layered architecture is to divide the design into smaller pieces. To reduce the design complexity, most networks are organized in a series of layers. The transport layer ($4^{th}$ from the base) is one of the seven layers of the OSI model.

The transport layer is the fourth layer of the OSI model which is responsible for the process to process delivery of data. The main aim of the transport layer is to maintain order so that the data must be received in the same sequence as it was sent by the sender. The transport layer provides two types of services namely – connection-oriented and connectionless.

The functions provided by the transport layer are as follows:

  • The transport layer maintains the order of data.
  • It receives the data from the upper layer and converts it into smaller parts known as segments.
  • One of the major tasks of the transport layer is to add the port addressing (addition of a port number to the header of the data). The port number is added so that the data can be sent to the respective process only.
  • The transport layer on the receiver’s end reassembles the segments to form the actual data.
  • The transport layer also deals with flow control and error control (discussed in the physical layer section).

Refer to the image below to see the basic transmission of data and working of the transport layer.

basic-transmission-and-working-of-transport-layer

The transport layer deals with the TCP. Let us now learn about the transmission control protocol or TCP.

The transmission control protocol is a transport layer connection-oriented protocol that defines the standard of establishing and maintaining the conversation (or connection) that will be used by the applications to exchange the data. The transmission control protocol is one of the most important and widely used protocols of the IP suite. The IP suite or the What is meant by Internet Protocol Suite?

The Internet Protocol Suite is the standard network model and stack of communication protocols that are used on the Internet. Hence, for the data transmission in the communication network, we use the transmission control protocol.

Refer to the image for more clarity.

tcp-ip-model


Note:
There are two types of connection namely connection-oriented and connection-less protocol. In the connection-oriented protocol, we first need to connect to the receiver before sending our data.

One of the prime reasons for using the transmission control protocol over other protocol(s) like UDP is that the TCP ensures the reliable transmission and delivery of our data packets. The transmission control protocol can deal with the various issues that can occur in data transmission such as packet duplication, packet corruption, packet disordering, packet loss, etc. The transmission control protocol is used with the internet protocols such as IPV4, IPV6, ICMP, etc. Let us now learn the working of the transmission control protocol. The transmission control protocol divides the data into the form of smaller bundles known as packets and then assigns some numbering to these packets. Finally, it transmits the packets of data to the receiver end. As we have discussed earlier, the transmission control protocol is connection-oriented. So, it needs to establish a connection before sending the packets.

To learn more about the TCP/IP model and its working, you can refer here.

Client-server Architecture

Let us now learn about client-server architecture. A client-server architecture is nothing but a type of model used in computer networking. An example of the client-server architecture can be accessed from any web page on the internet. In the client-server architecture, there is a client who sends a request to the server, and then there is a server that accepts the client’s request and then provides the requested data to the client. A Client is a computer system that accesses the services provided by a server. On the other hand, a server is a powerful centralized hub that stores various information and handles the requests of the client(s). A server can be on the same machine or can be a remote machine as well.

Let us now briefly discuss the client and server in brief before getting into the steps and TCP client-server implementation.

The client-server network model or architecture is one of the most widely used networking models. In the client-server network, the files are not stored on the hard drive of each computer system. Instead, the files are centrally stored and backed up on a specialized computer known as a server. Here, a server is designed to efficiently provide data to a remote client. On a large-scale network, there can be more than one server. Let us discuss the various types of servers:

  • File Server: A file server is used to transfer files to the client(s). A file server is a computer attached to a network that provides a location for shared disk access.
  • Email Server: An email server is used to deal with the internal email system. STMP deals with File Servers.
  • Web Server: A web server is used to control access to the internet and block any unsuitable websites. It accepts requests via HTTP or its secure variant HTTPS.
  • Print Server: A print server is used to deal with all of the printing requests from the client(s). It connects printers to client computers over a network.

In a client-server network, there is a specific server and specific clients connected to the server. Refer to the diagram below to see the basic overview of a client-server network system architecture.

client-server-network-model

The central computer system or the server is used to provide communication and resource sharing between other computer systems present on the network which are known as clients. A client does not share any of its resources, but it requests data or services from a server. The main focus of the client-server network model is on data sharing.

Note:

  • The client-server model is also known as the networking computing model as all the services and requests are delivered on the same or different network.
  • A system administrator is responsible for managing the data present on the server.


A server is always ON so client machines can access the files and resources without caring whether the server computer system is ON or not. One of the major drawbacks of the client-server model is that if the server is turned OFF (due to any certain reason), the resources present on the server will not be available to the clients.

Implementation

Let us now move into the TCP client-server implementation.

Steps

First, let us discuss the steps involved in the TCP client-server implementation.

  • Server-side implementation steps
    1. First we will create a socket with the help of a pre-defined socket() system call.
    2. After creating the socket() system call, we will initialize the address structure of the socket and then bind the address using a pre-defined system call namely – the bind() system call so that the socket is attached to the proper port number of the desired process.
    3. After making the connection, we need to listen to the connection. Now, for listening, we use another pre-defined system call i.e. listen().
    4. After listening, we need to accept the connection to the client and here we use the pre-defined system called accept() for the same. The main advantage of the accept() system call is that this system call blocks the line until a client connects to the server. If we want multiple connections then one connection is handled after the other.
    5. Now, we can easily send and receive data. For sending the data, we use the send() system call and for receiving the system call, the recv() system is used.
    6. At last, we end the connection from the server side using the pre-defined function i.e. close() function.
  • Client-side implementation steps
    1. First we will create a socket with the help of a pre-defined socket() system call so that the socket is attached to the proper port number of the desired process.
    2. After creating the socket() system call, we will initialize the address structure of the socket according to the server and then connect the newly created socket to the server’s address using another pre-defined system call namely – connect().
    3. Now, we can easily send and receive data. For sending the data to the server, we use the send() system call and for receiving the system call from the server, the recv() system is used.
    4. As we know in all the connections, we must end the connection so we must end the connection from the client side as well using the pre-defined function i.e. close() function.

Let us now move into the implementation in C language.

Server Side Code

// adding the necessary libraries.
#include <stdio.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#define MAX 80
#define PORT 8080
#define SA struct sockaddr

// A function created for chatting between client and server.
void func(int connectID)
{
    // defining a buffer of MAX size
    char buffer[MAX];
    int n;

    // infinite loop for chat
    for (;;)
    {
        bzero(buffer, MAX);

        // reading the message from the client and then copying it into the buffer.
        read(connectID, buffer, sizeof(buffer));

        // printing the buffer which contains the client response
        printf("From the client: %s\t To the client : ", buffer);
        bzero(buffer, MAX);

        n = 0;
        // copying the server message into the buffer using the while loop
        while ((buffer[n++] = getchar()) != '\n')
            ;

        // sending the copied buffer message to the client.
        write(connectID, buffer, sizeof(buffer));

        // Ending the chat if the message contains "Exit".
        if (strncmp("exit", buffer, 4) == 0)
        {
            printf("Closing Server\n");
            break;
        }
    }
}

// Defining the main function.
int main()
{
    int sockfd, connectID, length;
    struct socketAddress_in serverAddress, client;

    // creating a socket and verifying it.
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1)
    {
        printf("Socket not created!\n");
        exit(0);
    }
    else
        printf("Socket successfully created!\n");
    bzero(&serverAddress, sizeof(serverAddress));

    // assigning IP address, and PORT address.
    serverAddress.sin_family = AF_INET;
    serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
    serverAddress.sin_port = htons(PORT);

    // Binding newly created socket to given IP
    if ((bind(sockfd, (SA *)&serverAddress, sizeof(serverAddress))) != 0)
    {
        printf("Socket binding failed!\n");
        exit(0);
    }
    else
        printf("Socket binding done successfully!\n");

    // Now the server is ready to listen and verification
    if ((listen(sockfd, 5)) != 0)
    {
        printf("Listen failed!\n");
        exit(0);
    }
    else
        printf("Server listening!\n");
    length = sizeof(client);

    // Accept the data packet from the client and verification
    connectID = accept(sockfd, (SA *)&client, &length);
    if (connectID < 0)
    {
        printf("Server accept failed!\n");
        exit(0);
    }
    else
        printf("Server accept the client!\n");

    func(connectID);

    // finally closing the connection.
    close(sockfd);
}

Output:

Socket successfully created!
Socket binding is done successfully!
Server listening!
The server accepts the client!
From the client: hi
     To the client: hello
From the client: exit
     To the client: exit
Closing Server

Explanation

  • In the above server-side code, we first included the various necessary header files particularly socket programming necessary header files.
  • After that, we defined the PORT number of the server and the maximum buffer size that stores messages from the client and the server.
  • We then created a function that takes the connection ID and then runs an infinite loop and in each iteration, it reads the message from the client (using the predefined read() function), copied it to the buffer, and then prints it on the console. The Buffer is a region of memory used to temporarily hold data while it is being moved from one place to another. A buffer is used when moving data between processes within a computer.
  • Again we empty the buffer using a predefined function bzero().
  • We then check if the client wants to close the connection, if the client enters exit then we close the connection and break else the iteration continues.

Now, in the main() function,

  • We first create a socket using the pre-defined function socket() and then check if the connection is successfully created or not. If the connection is successfully created then we proceed further else we exit the program.
  • We then bind the newly created socket to the given IP. Similar to the socket definition, if the binding is done successfully then we proceed further else we exit the program.
  • Now, after the binding, we start listening to the port and verify the connection. After successful listening, we accept the connection using the pre-defined function accept() and then call the function func() by providing the connection ID.
  • At last, we close the connection using the close() function.

Client-side Code

// adding the necessary libraries.
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/socket.h>
#include <unistd.h>

#define MAX 80
#define PORT 8080
#define SA struct socketAddress

// A function created for chatting between client and server.
void func(int sockfd)
{
    // defining a buffer of MAX size
    char buffer[MAX];
    int n;

    // infinite loop for chat
    for (;;)
    {
        bzero(buffer, sizeof(buffer));

        // Getting the message.
        printf("Enter the string: ");
        n = 0;

        // copying the server message into the buffer using the while loop
        while ((buffer[n++] = getchar()) != '\n')
            ;

        // sending the copied buffer message.
        write(sockfd, buffer, sizeof(buffer));
        bzero(buffer, sizeof(buffer));

        // reading the message.
        read(sockfd, buffer, sizeof(buffer));
        printf("From the server : %s", buffer);

        // Ending the chat if the message contains "Exit".
        if ((strncmp(buffer, "exit", 4)) == 0)
        {
            printf("Closing Client\n");
            break;
        }
    }
}

// Defining the main function.
int main()
{
    int sockfd, connfd;
    struct socketAddress_in socketAddress, cli;

    // socket creation and verification
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1)
    {
        printf("Socket not created!\n");
        exit(0);
    }
    else
        printf("Socket successfully created!\n");
    bzero(&socketAddress, sizeof(socketAddress));

    // assigning IP address, and PORT address.
    socketAddress.sin_family = AF_INET;
    socketAddress.sin_addr.s_addr = inet_addr("127.0.0.1");
    socketAddress.sin_port = htons(PORT);

    // connecting the client socket to the server socket.
    if (connect(sockfd, (SA *)&socketAddress, sizeof(socketAddress)) != 0)
    {
        printf("Connection with the server failed!\n");
        exit(0);
    }
    else
        printf("Connected to the server!\n");

    func(sockfd);

    // finally closing the connection.
    close(sockfd);
}

Output:

Socket successfully created!
Connected to the server!
Enter the string: hi
From the server: hello
Enter the string: exit
From the server: exit
Closing Client

Explanation

  • In the above client-side code, we first included the various necessary header files particularly socket programming necessary header files.
  • After that, we defined the PORT number of the client and the maximum buffer size that stores messages from the client and the server.
  • We then created a function that runs an infinite loop and in each iteration, it accepts the message from the server and copies it to the buffer, and then writes the message on the buffer defined previously.
  • Again we empty the buffer using a predefined function bzero() so that a fresh new request can be dealt with.
  • We then read the message of the buffer and then print it on the console.
  • We then check if the server wants to close the connection, if the server enters exit then we close the connection and break else the iteration continues.

Now, in the main() function,

  • We first create a socket using the pre-defined function socket() and then check if the connection is successfully created or not. If the connection is successfully created then we proceed further else we exit the program.
  • We then assign the IP address, PORT number, etc to the socket and then try to connect to the server using the pre-defined function connect(). Similar to the socket one, if the connection is successful then we continue to proceed further, else we break from the program because without a proper connection we cannot request the data from the server.
  • At last, we close the connection using the close() function.

Additional Resources

We have a lot more content on the server, client, their connection, OSI model, TCP/IP model, and whatnot. Please refer to the links provided below to learn more content related to computer networking on Scaler Topics!

Conclusion

  • The communication between different processes on the same nodes or different nodes is done using the concept of a socket. A socket is a structure that allows communication between processes i.e. sending and receiving data over a network.
  • A socket can be defined as an endpoint present in a two-way communication link (present between two processes running on the network).
  • The transmission control protocol is a transport layer connection-oriented protocol that defined the standard of establishing and maintaining the conversation (or sockets) that will be used by the applications to exchange the data.
  • The client-server network model or architecture is one of the most widely used networking models. In the client-server network, the files are not stored on the hard drive of each computer system.
  • In a client-server network, there is a specific server and specific clients connected to the server. A server is always ON so client machines can access the files and resources without caring whether the server computer system is ON or not.
  • One of the prime reasons for using the transmission control protocol over other protocol(s) like UDP is that the TCP ensures the reliable transmission and delivery of our data packets.

Author