build a tcp server with C

HacksLand | The computer science playground

Posted by Thilan Dissanayaka on May 01, 2020

Socket programming is one of most important feature in C. In this document we are going to build a simple tcp server using 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. Hear is the definition of bind function.

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

First argument is the previous generated (returned from socket function. ) file descriptor . 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. Last argument is the length of address of the structure. We can simply use sizeof() function to get it.

Let's make a the 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 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 given port.

int listen(int sockfd, int backlog);

Above definition  indicates, we need to supply two arguments. First one is previously opened file descriptor. Second is backlog number This is the maximum number of waiting connections.

Now we have coded 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 address 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 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 hear. 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.

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

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

First argument is previously created file descriptor (returned from socket() function). Second argument is again a address structure. Third is that structure's address length. We know this return a file descriptor on success So we need to define another integer to save this file descriptor. Also we need another structure that created with above sockaddr_in structure.

So if we successfully connect with this accept function, we can send and receive some data though 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 binded 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 it 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 next article we are going to make a tcp client to connect to this server.

Hi, I'm Thilan. An engineering student from SriLanka. I love to code with Python, JavaScript PHP and C.

Also read

Aug 12
Comments in C

Every programming language has comments .In python tutorial we used # for indicating a....

Apr 16
Wordpress nulled theme checker

We all love free stuff. So many people try to install premium themes and plugins on there WordPress....

Aug 12
Debugging Binaries with GDB

GDB is shipped with te GNU tool set. It is a debugging tool used in Linux environments. The term....

Comments