Mar 09, 2022

How to build a basic tcp server in c

Socket programming is one of the most important features in C. In this document, we are going to build a simple TCP server using the C language for Linux platforms. For that we use socket library comes for Unix/Linux.

Two networked devices connect through a socket. Following is what man pages say about socket() function.

man-page-socket

You can see it expects three arguments and return a file descriptor. (A file descriptor is just an integer with unique value)

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

First argument is domain. This indicate the protocol family. We can use protocol families like AF_INET , AF_INET6 etc. AF_INET stands for IP version four.  You know that a version four IP is something like 192.168.56.101. (This is what we are using right now) . As you guessed AF_INET6 stands for IP version six.

Second argument is protocol type. We can use tcp, udp etc. In this document we are going to use tcp.  The term SOCK_STREAM  is used to indicate  tcp (TCP stands for Transmission Control Protocol).

Now let's begin with coding our server. First I use socket function to open a socket. If socket function successfully open a socket it'll return a file descriptor, otherwise it return -1. So we can know the result by checking the return value of socket function as following.

int fd;

if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
        printf("%s\n", "Socket creating failed!");
        exit(0);
}else{
        printf("%s\n", "Socket created successfully!");
}

OK. Now we have created a socket with no address is assigned. We can access it with the file descriptor we got. Next, we use bind() function to bind a port with socket. Here is the definition of bind function.

int bind(int sockfd, const struct sockaddr *addr,
                socklen_t addrlen);

The first argument is the previous generated (returned from socket function. ) file descriptor. The second argument is a pointer to a structure.  This is a specific structure (Named as sockaddr_in ) declared in xxxxxx header file to hold address data. Before we use it in the bind function we must declare this structure and assign values to it. We have to use typecasting to convert it to sockaddr type. The last argument is the length of the address of the structure. We can simply use sizeof() function to get it.

Let's make a new structure and add values to it.

struct sockaddr_in serv_addr
serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(4444);

Hear you know sin_family is the protocol family. sin_addr.s_addr is the IP address of current mashing. Finally, sin_port is the port we use to serve the service.

OK. Let's see how we can use the bind function.

if (bind(fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) == -1){
        printf("%s\n", "Socket binding failed!");
}else{
        printf("%s\n", "Socket binding successful!");
}

Now our socket is ready to receive connections. We use listen() function to turn on listening on the given port.

int listen(int sockfd, int backlog);

The above definition indicates we need to supply two arguments. First one is the previously opened file descriptor. The second is backlog number Which is the maximum number of waiting connections.

Now we have coded the first part of our tcp server We used socket() function to create a new socket. Then created a structure with address data and used bind() function to bind local addresses to it. Then we used listen() function to turn on listening mode on our socket At the moment a remote client can connect to our newly created server. In the following code, we can see the complete code for the above process.

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


#define PORT 4444


int main(int argc, char const *argv[])
{       int fd;
        struct sockaddr_in serv_addr;

        if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
        {
                printf("%s\n", "Socket creating failed!");
                exit(0);
        }else{
                printf("%s\n", "Socket created sucessfully!");
                serv_addr.sin_family = AF_INET;
                serv_addr.sin_addr.s_addr = INADDR_ANY;
                serv_addr.sin_port = htons(PORT);

                if (bind(fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) == -1){
                        printf("%s\n", "Socket binding failed!");
                }else{
                        printf("%s\n", "Socket binded sucessfully!");
                        listen(fd,5);
                           
                }
        }

        return 0;
}

You can see I have included some header files here. You know we need stdio.h for printing strings and stdlib.h for exit() function. socket, bind, and listen functions are defined in types.h and socket.h.  We need netinet/in.h because the address structure is defined there. You may use man pages to see which header files you need to include to use a specific function.

The next step is to give some functions to our simple server. For that, we need to accept connections from clients. For that, we use accept() function. This also requires three arguments and returns a file descriptor on success If it fails to accept the connection, it will return -1.

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

The first argument is the previously created file descriptor (returned from socket() function). The second argument is again an address structure. The third is the structure's address length. We know this returns a file descriptor on success So we need to define another integer to save this file descriptor. Also, we need another structure that was created with the above sockaddr_in structure.

So if we successfully connect with this accept function, we can send and receive some data through this socket.

 

Following is the complete code to do that.

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


#define PORT 4444


int main(int argc, char const *argv[])
{       int fd, fd2, clilen;
        struct sockaddr_in serv_addr, cli_addr;
        char buff[1000];

        if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
        {
                printf("%s\n", "Socket creating failed!");
                exit(0);
        }else{
                printf("%s\n", "Socket created sucessfully!");
                serv_addr.sin_family = AF_INET;
                serv_addr.sin_addr.s_addr = INADDR_ANY;
                serv_addr.sin_port = htons(PORT);

                if (bind(fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) == -1){
                        printf("%s\n", "Socket binding failed!");
                }else{
                        printf("%s\n", "Socket bound sucessfully!");
                        listen(fd,5);
                        
                        clilen = sizeof(cli_addr);

                        if ((fd2 = accept(fd, (struct sockaddr *) &cli_addr, &clilen)) == -1){
                                printf("%s\n", "Accepting failed!");
                                exit(0);
                        }else{
                                for (;;)
                                {
                                        bzero(buff, sizeof(buff));
                                        if ((read(fd2,buff, sizeof(buff))) == -1){
                                                printf("%s\n", "Reading from socket failed!");
                                                exit(0);
                                        }else{
                                                printf("Message from client: %s\n",buff);
                                                bzero(buff, sizeof(buff));
                                                fgets(buff, sizeof(buff), stdin);

                                                if (strncmp(buff, 'exit') == 0)
                                                {
                                                        close(fd);
                                                        exit(0);     
                                                }
                                        
                                                if (write(fd2, buff ,sizeof(buff)) == -1) {
                                                        printf("%s\n", "Writing to socket failed!");
                                                        exit(0);
                                                }

                                        }
                                }
     
                        }
                        
                }
        }

        return 0;
}

Now it is time to test it out At the moment we don't have a client program. So I use our Netcat tool to test it.

I compiled the server program in protostar Linux mashing and ran it. So you can see it is waiting for connections.

tcp-server-waiting-connections

Hear I send some data from my backtrack mashing I use it as the client mashing.

tcp-server-send-massage-from-nc

 

hjghj

tcp-server-recived-massage

In the next article, we are going to make a TCP client which can be used to connect to this server.

Mar 08
Complex number program in C++ using class

In this tutorial, we are going to see how we can write a complex number program in c++ using the....

Apr 09
C programming array tutorial

In a previous article we discussed how we can declare and use variables in C. We know a variable is....

Jun 21
Protostar Stack1 Tutorial

In previous tutorial I completely explained how to exploit protostar stack 0 vulnerable program. In....

Replying to 's comment Cancel reply
ABOUT AUTHOR
Thilan Danushka Dissanayaka

Thilan Dissanayaka

Hi, I'm Thilan from Srilanka. An undergraduate Engineering student of University of Ruhuna. I love to explorer things about CS, Hacking, Reverse engineering etc.

CATEGORIES
SOCIAL
RANDOM ARTICLES