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

Advertisements

Sockets in C – an Introduction

The story of Internet

The comic says it all.

Le expertly made ragecomic

internet troll

Internet has transformed the human civilization. It has made computers more powerful and wide-reaching than ever. So much so that we have computers made for just the internet like “Netbooks” or a “Chromebook”

Sockets, what are they ?

Sockets are the primary way to communicate between two computers/devices. They can be though of as a long invisible pipe between 2 computers through which all of their messages are exchanged. Needless to say, to communicate , both computers need to have a socket opened.

Linux has 3 types of sockets

SOCK_STREAM

Corresponds to a TCP connection. Basically we get sure shot message delivery , without errors and we have to establish a connection before we can communicate. Incase some error occurs ( like connection is lost or if one device can’t find the other ), devices are notified with errors. The main idea is, if we send something without getting an error , we can be reasonably sure that out message has reached. The whole process is similar to making a phone call.It’s good for exchanging data like email,text or programs.

SOCK_DGRAM

Corresponds to a UDP connection. In this case nothing is sure . After sending a message the best we can do is pray that the message reaches, the socket does nothing to ensure a sure shot delivery.Even if it does, data might be out-of-order or incorrect. Although we might discover sometimes that most messages do make it, nobody guarantees that. For eg, a router can start discarding packets if it senses congestion, and the sending party won’t make an attempt to send it back.It’s like a couple having a break-up through Postal Service. Messages may not reach, moreover nobody cares 😛 . Good for large data, like audio/video. A video may contain millions of pixels, nobody would mind a few misplaced ones, our eyes would hardly notice

SOCK_SEQPACKET

Similar to SOCK_STREAM , but the only major difference is the message size is preserved. If a SOCK_STREAM socket gets 2 messaged of 10 and 15 bytes, when the receiver tries to read it, he will get 25 bytes together. In case of SOCK_SEQPACKET the receiver will get 10 bytes the first time he reads and even though 15 bytes have arrived, they will only be available to him after he has read the first 10 bytes. In simple terms , message lengths are preserved.

IP Address and Port Numbers

Since Computers don’t speak any human language they never call each other as how we know them. The Internet Protocol ( IP ) requires each computer on the planet ( or wherever ) to have a unique address known as the IP address ( eg 234.15.67.211 ).

One computer can be connected to many other computers. To give an example , you might be using Facebook , chatting on Skype and playing DOTA at the same time. In addition to an IP Address, a connection is identified by a port number .

Don’t believe me ?

Try connecting to Port 80 on Computer 173.194.38.146

173.194.38.146:80
 

To get started with coding ,go to my post here

.