C Socket Tutorial – Echo Server

Following my previous post here , I’ll get to the programming part.But before that a few concepts that are important.

Client Server Model

Anytime two devices want to connect through a TCP/IP socket , one of them has to be a client and the other has to be a server. As an example your computer might be the client and Google computer might be the server. The client should be aware of the Server’s IP Address and Port Number, while the server can accept any client and determine his IP later.

File Descriptors, not just for files

As the name suggests file descriptors hold information about a file, but not just files, Adhering to Unix’s philosophy of everything is a file, all I/O is done through file descriptors from the programmer’s side. This can include access to USB ports, Hard Disks , Optical Drives , Cameras and most importantly Network Connections. What this means is , no matter which of these you access, programmer can assume that they are files and live in blissful oblivion. The actual work on the other hand is done by , the Programmer’s true friend, the Silent Guardian , the Operating System.

In Linux file-descriptors are accessed with their corresponding integers. Three of them are reserved by default for special files.

0 – Standard Input – Analogous to theĀ  keyboard, whatever the user types from they keyboard can be read from this file descriptor.

1 – Standard Output- Whatever you write to this file descriptor , appears as text on the console.

2 – Standard Error – To display error messages.

The above three also come into play while dealing with pipes. For a more detailed reference , go to Wikipedia.

A simple program to illustrate file descriptors.

Hello File Descriptors


/* Not stdio.h */
#include <unistd.h>

void main()
{
	char str[100];

	/*Write on screen*/
	write(1,"\nType Something : ",17);

	/*Read at most 100 chars from console into 'str' */
	read(0,str,100);

	write(1,"\nYou typed :\n",13);

	/*write 10 chars from 'str' to screen */
	write(1,str,10);

	/*newline*/
	write(1,"\n",1);
}

Output – For the lazy ones


Type Something :hi how are you

You typed :
hi how are

read/write


write(int fd, const void *buf, size_t n);

fd – File Descriptor to write to
buf – Pointer to Data to be written
n – Number of bytes to write
returns – Number of bytes written, negative if error


read(int fd, const void *buf, size_t n);

fd – File Descriptor to read from
buf – Pointer to where data read should be stored
n – Maximum number of bytes to be read.
returns – Number of bytes read, can be less than n if there is end of input , negative if error

Lets get to handling sockets now.

Hello Sockets – Echo Server

Echo Server is a device which sends back whatever data it has received
I have put comments in the code to explain what each function does. Apart from that I recommend you Google each of them to know their prototype , as I won’t be mentioning them , or you can use man in Linux.

/*Required Headers*/

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include<string.h>

int main()
{

	char str[100];
	int listen_fd, comm_fd;

	struct sockaddr_in servaddr;

	listen_fd = socket(AF_INET, SOCK_STREAM, 0);

	bzero( &servaddr, sizeof(servaddr));

	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htons(INADDR_ANY);
	servaddr.sin_port = htons(22000);

	bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));

	listen(listen_fd, 10);

	comm_fd = accept(listen_fd, (struct sockaddr*) NULL, NULL);

	while(1)
	{

		bzero( str, 100);

		read(comm_fd,str,100);

		printf("Echoing back - %s",str);

		write(comm_fd, str, strlen(str)+1);

	}
}

Line by Line

int listen_fd, comm_fd;

File Descriptors to be used

struct sockaddr_in servaddr;

Struct to hold IP Address and Port Numbers

listen_fd = socket(AF_INET, SOCK_STREAM, 0);

Each server needs to “listen” for connections. The above function creates a socket with AF_INET ( IP Addressing ) and of type SOCK_STREAM. Data from all devices wishing to connect on this socket will be redirected to listen_fd.

bzero( &servaddr, sizeof(servaddr));

Clear servaddr ( Mandatory ).

servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htons(INADDR_ANY);
servaddr.sin_port = htons(22000);
  • Set Addressing scheme to – AF_INET ( IP )
  • Allow any IP to connect – htons(INADDR_ANY)
  • Listen on port 22000 – htons(22000)

[ Remember how Google listened on Port 80 ? ]

bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));

Prepare to listen for connections from address/port specified in sockaddr ( Any IP on port 22000 ).

listen(listen_fd, 10);

Start Listening for connections , keep at the most 10 connection requests waiting.If there are more than 10 computers wanting to connect at a time, the 11th one fails to.

comm_fd = accept(listen_fd, (struct sockaddr*) NULL, NULL);

Accept a connection from any device who is willing to connect, If there is no one who wants to connect , wait. A file descriptor is returned. This can finally be used to communicate , whatever is sent by the device accepted can be read from comm_fd, whatever is written to comm_fd is sent to the other device.

	bzero( str, 100);
	read(comm_fd,str,100);
	printf("Echoing back - %s",str);
	write(comm_fd, str, strlen(str)+1);

The Server then does the above forever

  • Clear str
  • read at most 100 bytes into str
  • display what it reads
  • send back str , (length of string + 1) so that is sent as well

Hello Sockets – Client


#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include<string.h>

int main(int argc,char **argv)
{
	int sockfd,n;
	char sendline[100];
	char recvline[100];
	struct sockaddr_in servaddr;

	sockfd=socket(AF_INET,SOCK_STREAM,0);
	bzero(&servaddr,sizeof servaddr);

	servaddr.sin_family=AF_INET;
	servaddr.sin_port=htons(22000);

	inet_pton(AF_INET,"127.0.0.1",&(servaddr.sin_addr));

	connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));

	while(1)
	{
		bzero( sendline, 100);
		bzero( recvline, 100);
        fgets(sendline,100,stdin); /*stdin = 0 , for standard input */

        write(sockfd,sendline,strlen(sendline)+1);
        read(sockfd,recvline,100);
        printf("%s",recvline);
	}

}

Line by Line

I’ll only go over the new parts

inet_pton(AF_INET,"127.0.0.1",&(servaddr.sin_addr));

Set IP address in servaddr to “127.0.0.1” ( computers way of saying myself ) since our server is also on the same machine . The address in servaddr needs to be in integer format , hence the function inet_pton

connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));

Connect to the device whose address and port number is specified in servaddr.

bzero( sendline, 100);
bzero( recvline, 100);
fgets(sendline,100,stdin); /*stdin = 0 , for standard input */
write(sockfd,sendline,strlen(sendline)+1);
read(sockfd,recvline,100);
printf("%s",recvline);

The Client then does following forever.

  • Clear sendline and recvline
  • read string from stdin in sendline ( stdin is 0 for standard input )
  • write sendline in sockfd
  • read from sockfd in srecvline
  • Display recvline

Output – Client/Server in a not so pleasant Conversation


Hi Server
Hi Server
How are you ?
How are you ?
Stop imitating me !!!
Stop imitating me !!!
STAAAAHHPPPPPPPP !
STAAAAHHPPPPPPPP !

I hope this post is of some help to whoever reads it. I tried to keep it as simple as possible . Leave Comments