TCP Client-Server Implementation in C

In this tutorial, you will learn to implement a TCP client-server program in the C programming language. Here, the client and server would exchange messages and communicate with each other in an interactive way. In addition, you will also learn about the client-server architecture and other related concepts.

Table of Content

  1. What is a socket?
  2. What is TCP?
  3. Client-server Architecture.
  4. Implementation
  5. Further Reading
  6. Summary

What is a Socket?

A socket is a structure that allows communication between different processes on the same computer or different computers. A socket allows us to communicate by sending and receiving data over the network. In simple terms, it is a way for a computer to talk to other computers on the network.

socket is one endpoint of a two-way communication link between two programs running on the network. A socket is bound to a port number so that the TCP layer can identify the application that data is destined to be sent to.

https://docs.oracle.com/javase/tutorial/networking/sockets/definition.html

What is TCP?

TCP refers to the Transmission Control Protocol. It is one of the main protocol used for communication over the internet. Some of the features of this protocol are:

  • It is a connection-oriented communication protocol.
  • It used three-way handshake to establish reliable connections.
  • TCP gurantees the delivery of the data packets.

Client-server Architecture

A client-server architecture is a model in computer networking, where the server provides some service to the client. In this architecture, the client computer sends a request to the server computer through a network (internet). The server accepts this request and sends the required data to the client.

In simple terms, we can say

  • Server is a remote computer which provides some services.
  • Client is the one that request the server for these services.

Implementation

Here, we will start the implementation of the client-server implementation in C. First, we start by implementing the server-side and then we begin with the client-side code.

Server-Side Code

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

int main(){

  char *ip = "127.0.0.1";
  int port = 5566;

  int server_sock, client_sock;
  struct sockaddr_in server_addr, client_addr;
  socklen_t addr_size;
  char buffer[1024];
  int n;

  server_sock = socket(AF_INET, SOCK_STREAM, 0);
  if (server_sock < 0){
    perror("[-]Socket error");
    exit(1);
  }
  printf("[+]TCP server socket created.\n");

  memset(&server_addr, '\0', sizeof(server_addr));
  server_addr.sin_family = AF_INET;
  server_addr.sin_port = port;
  server_addr.sin_addr.s_addr = inet_addr(ip);

  n = bind(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr));
  if (n < 0){
    perror("[-]Bind error");
    exit(1);
  }
  printf("[+]Bind to the port number: %d\n", port);

  listen(server_sock, 5);
  printf("Listening...\n");

  while(1){
    addr_size = sizeof(client_addr);
    client_sock = accept(server_sock, (struct sockaddr*)&client_addr, &addr_size);
    printf("[+]Client connected.\n");

    bzero(buffer, 1024);
    recv(client_sock, buffer, sizeof(buffer), 0);
    printf("Client: %s\n", buffer);

    bzero(buffer, 1024);
    strcpy(buffer, "HI, THIS IS SERVER. HAVE A NICE DAY!!!");
    printf("Server: %s\n", buffer);
    send(client_sock, buffer, strlen(buffer), 0);

    close(client_sock);
    printf("[+]Client disconnected.\n\n");

  }
  return 0;
}

The server-side process can be broken down into the following steps:

  1. socket() – create TCP socket.
  2. bind() – bind the TCP socket to the server address (ip and port).
  3. listen() – waiting for the clients.
  4. accept() – connection is established between the client and server.
  5. recv() and send () – communicate with each other.
  6. close() – close the connection from the client.

Include the required header files.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

Define the IP (Internet Protocol) address and port number, that would be used to create a socket. Here, we are using the localhost address for both the server and the client.

char *ip = "127.0.0.1";
int port = 5566;

Here, we define the required variables used later in this program.

int server_sock, client_sock;
struct sockaddr_in server_addr, client_addr;
socklen_t addr_size;
char buffer[1024];
int n;

Create a TCP (Transmission Control Protocol) socket that returns a socket descriptor. This socket descriptor would be used to communicate with the client.

server_sock = socket(AF_INET, SOCK_STREAM, 0);
if (server_sock < 0){
  perror("[-]Socket error");
  exit(1);
}
printf("[+]TCP server socket created.\n");

Here, we initialize the server address by providing the required IP and port number. The server keeps all the address information for both the server and the client in the sockaddr_in struct.

memset(&server_addr, '\0', sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = port;
server_addr.sin_addr.s_addr = inet_addr(ip);

Binding the socket descriptor with the server address information.

n = bind(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr));
if (n < 0){
  perror("[-]Bind error");
  exit(1);
}
printf("[+]Bind to the port number: %d\n", port);

Now, we listen for incoming connections from the clients.

listen(server_sock, 5);
printf("Listening...\n");

The server handles only one client at a time. So, only one client would communicate and the rest would have to wait for the communication to get completed.

while(1){
  addr_size = sizeof(client_addr);
  client_sock = accept(server_sock, (struct sockaddr*)&client_addr, &addr_size);
  printf("[+]Client connected.\n");

  bzero(buffer, 1024);
  recv(client_sock, buffer, sizeof(buffer), 0);
  printf("Client: %s\n", buffer);

  bzero(buffer, 1024);
  strcpy(buffer, "HI, THIS IS SERVER. HAVE A NICE DAY!!!");
  printf("Server: %s\n", buffer);
  send(client_sock, buffer, strlen(buffer), 0);

  close(client_sock);
  printf("[+]Client disconnected.\n\n");
  }

To communicate with all the clients, we start a while loop and the following things happen:

  • Accept the client connection.
  • We receive a message from the client and print it on the console.
  • Next, the server send a reply message to the client.
  • Close connection from the client.

The following sequences go on with other clients.

Client-Side Code

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

int main(){

  char *ip = "127.0.0.1";
  int port = 5566;

  int sock;
  struct sockaddr_in addr;
  socklen_t addr_size;
  char buffer[1024];
  int n;

  sock = socket(AF_INET, SOCK_STREAM, 0);
  if (sock < 0){
    perror("[-]Socket error");
    exit(1);
  }
  printf("[+]TCP server socket created.\n");

  memset(&addr, '\0', sizeof(addr));
  addr.sin_family = AF_INET;
  addr.sin_port = port;
  addr.sin_addr.s_addr = inet_addr(ip);

  connect(sock, (struct sockaddr*)&addr, sizeof(addr));
  printf("Connected to the server.\n");

  bzero(buffer, 1024);
  strcpy(buffer, "HELLO, THIS IS CLIENT.");
  printf("Client: %s\n", buffer);
  send(sock, buffer, strlen(buffer), 0);

  bzero(buffer, 1024);
  recv(sock, buffer, sizeof(buffer), 0);
  printf("Server: %s\n", buffer);

  close(sock);
  printf("Disconnected from the server.\n");

  return 0;
}

The client-side process can be broken down into the following steps:

  1. socket() – create TCP socket.
  2. connect() – connect to the server.
  3. recv() and send () – communicate with each other.
  4. close() – close the connection.

We begin by including all the required header files, defining the IP (Internet Protocol) address and the port number. We also define the required variable used later in this program.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

NOTE: Make sure that the IP address and the port number for the client are the same as the server.

char *ip = "127.0.0.1";
int port = 5566;

int sock;
struct sockaddr_in addr;
socklen_t addr_size;
char buffer[1024];
int n;

We start by creating a TCP (Transmission Control Protocol) socket. The socket would be used to connect to the server and start communication.

sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0){
  perror("[-]Socket error");
  exit(1);
}
printf("[+]TCP server socket created.\n");

We provide the required IP address and the port number to the required data structures.

memset(&addr, '\0', sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = port;
addr.sin_addr.s_addr = inet_addr(ip);

We send a connection request to the server and wait for the server to accept the request.

connect(sock, (struct sockaddr*)&addr, sizeof(addr));
printf("Connected to the server.\n");

We send a message to the server and wait for the reply.

bzero(buffer, 1024);
strcpy(buffer, "HELLO, THIS IS CLIENT.");
printf("Client: %s\n", buffer);
send(sock, buffer, strlen(buffer), 0);

We receive the reply from the server and print it on the console.

bzero(buffer, 1024);
recv(sock, buffer, sizeof(buffer), 0);
printf("Server: %s\n", buffer);

At last, we close the connection from the server.

close(sock);
printf("Disconnected from the server.\n");

Further Reading

Summary

In this tutorial, you have learned to implement the TCP client-server architecture in the C programming language.

Still, have some questions or queries? Just comment below. For more updates. Follow me.

Leave A Comment