This article contains programs illustrating echo server application in C using socket programming.
This echo server prints the messages received by it on the screen as well as sent those messages back to the sender. And sender will print the messages on its screen before sending to echo server and after receving from echo server.
For beginners in socket programming, I explained basics of it before presenting code. Those who are already aware can directly jump to code section.
Socket programming
is a popular style of programming in networking domain. Two computers communicate each other using socket programming. And this communication is independant of programming language used for implementing it. And this is the main reason behind it's popularity. So, a program written in Java can communicate with a program written in C using sockets.
These sockets provide an interface for programming at the transport layer. Transport layer uses TCP and/or UDPprotocols for communication. Now, we can formally answer the Question:
What is socket
programming?
It is a
communication mechanism between two computers using protocols like
TCP or UDP.
But, what is a socket??!
socket is an end
point of communication across a computer network.
So, socket
programming can be visualized as a telephone line from telephone
operator to many different users with sockets acting as a separate
telephone numbers for every user.
Every socket will
have an address. And this address is comprised of two parts. One is
IP address and other is port number. This address is nothing but like
a telephone number with a particular extension to connect directly to
a particular user.
Now, we need two machines for communication and a program through which they will communicate with other.
Section A: This covers echo server using TCP protocol in C.
Steps to run the programs:
1. Copy this code and save it in a file with name as 'echo_server.c'
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
int main(void)
{
int clientfd = 0,connfd = 0;
int n = 0;
struct sockaddr_in serv_addr;
char buffer[1024];
clientfd = socket(AF_INET, SOCK_STREAM, 0);
printf("socket retrieve success\n");
memset(&serv_addr, '0', sizeof(serv_addr));
memset(buffer, '0', sizeof(buffer));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(5000);
bind(clientfd, (struct sockaddr*)&serv_addr,sizeof(serv_addr));
if(listen(clientfd, 10) == -1){
printf("Failed to listen\n");
return -1;
}
connfd = accept(clientfd, (struct sockaddr*)NULL ,NULL);
while(1)
{
read(connfd, buffer, sizeof(buffer));
write(connfd, buffer, sizeof(buffer));
fputs(buffer,stdout);
}
close(connfd);
return 0;
}
2. Copy this code and save it in a file with name as 'echo_client.c'
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#define BLOCK_SIZE 1024
int main(void)
{
int serverfd = 0,n = 0;
struct sockaddr_in serv_addr;
char buffer[BLOCK_SIZE];
int revCnt = 0;
memset(buffer, '0' ,sizeof(buffer));
if((serverfd = socket(AF_INET, SOCK_STREAM, 0))< 0)
{
printf("\n Error : Could not create socket \n");
return 1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(5000);
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
if(connect(serverfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))<0)
{
printf("\n Error : Connect Failed \n");
return 1;
}
do
{
fgets(buffer, sizeof(buffer), stdin);
write(serverfd, buffer, sizeof(buffer));
//memset(buffer,'0',sizeof(buffer));
read(serverfd, buffer, sizeof(buffer));
fputs(buffer, stdout);
fflush(stdin);
printf("\n");
}while(strcmp(buffer,"bye\n")!=0);
return 0;
}
3. Compile these two programs in two seperate terminals in a linux based machine. Following are the commands. These commands will create object file with the name provided. In this case 'server' and 'client' are object files.
gcc echo_server.c -o server
gcc echo_client.c -o client
Here, each terminal will act as a machine. And now these two terminals communicate with each other using sockets. These terminals are nothing but two processes in a operating system. So, socket programming is known for inter process communication.
4. Next, run the programs using following commands in each of the terminals:
./server
./client
Section B: This covers echo server using UDP protocol
1. Copy and save code in a file 'udp_server.c'
#include <sys/socket.h>
#include <sys/types.h>
#include <resolv.h>
#include <string.h>
#define BUFSIZE 200
int main()
{
int sd = 0;
char buffer[BUFSIZE];
int recvlen = 0;
struct sockaddr_in server_socket;
struct sockaddr_in rem_socket;
socklen_t addrlen = sizeof(rem_socket);
sd = socket(AF_INET, SOCK_DGRAM, 0);
printf("socket created\n");
memset(&server_socket, 0, sizeof(server_socket));
server_socket.sin_family = AF_INET;
server_socket.sin_port = htons(5000);
server_socket.sin_addr.s_addr = INADDR_ANY;
bind(sd, (struct sockaddr*)&server_socket,sizeof(server_socket));
do
{
recvlen = recvfrom(sd, buffer, BUFSIZE, 0, (struct sockaddr *)&rem_socket, &addrlen);
if (recvlen > 0)
{
buffer[recvlen] = 0;
fputs(buffer,stdout);
}
sendto(sd, buffer, sizeof(buffer), 0, (struct sockaddr *)&rem_socket, addrlen);
}while(strcmp(buffer,"bye\n")!=0);
close(sd);
return 0;
}
2. Copy and save code in a file 'udp_client.c'
#include <sys/socket.h>
#include <sys/types.h>
#include <resolv.h>
#include <string.h>
#define BUFSIZE 200
int main(void)
{
char buffer[200];
int sd = 0;
struct sockaddr_in client_socket;
struct sockaddr_in rem_socket;
socklen_t addrlen = sizeof(rem_socket);
int recvlen = 0;
if((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
printf("socket not created\n");
}
printf("socket created\n");
memset(&client_socket, 0, sizeof(client_socket));
client_socket.sin_family = AF_INET;
client_socket.sin_port = htons(5000);
client_socket.sin_addr.s_addr = inet_addr("127.0.0.1");
do
{
memset(buffer, '0', sizeof(buffer));
fgets(buffer,sizeof(buffer),stdin);
if (sendto(sd, buffer, sizeof(buffer), 0, (struct sockaddr *)&client_socket, sizeof(client_socket)) < 0)
{
printf("sendto failed");
return 0;
}
//fputs(buffer,stdout);
recvlen = recvfrom(sd, buffer, BUFSIZE, 0, (struct sockaddr *)&rem_socket, &addrlen);
if (recvlen > 0)
{
buffer[recvlen] = 0;
fputs(buffer,stdout);
}
}while(strcmp(buffer,"bye\n")!=0);
close(sd);
return 0;
}
3. Compile these two files in two separate terminals. Commands are as follows:
gcc udp_server.c -o udp_server
gcc udp_client.c -o udp_client
4. Run the programs as follows:
./udp_server
./udp_client
Congrats..!! You have successfully ran your first echo server using TCP as well as UDP
protocol in C!!
Messages you type in the 'client' terminal will get
printed in 'server' terminal and also these will be sent back by
'server' to 'client' and get printed in 'client' terminal.
Section C: How these programs work
Server machine implements following steps:
1. Create a socket.
2. Assign family, type and port number to the created socket.
3. Bind the socket.
4. Once request from a client comes at the port number mentioned in step 2 then accept it.
5. Receive the messages. Print it to the screen and sent it back to the corresponding client until message saying 'bye' is received.
The difference between TCP server and UDP server is that step no. 4 is absent in UDP server. why?
TCP is a connection oriented protocol. So a connection is always ensured before
communication between client and server in a TCP which is done by above step no. 4. While UDP is a connectionless protocol. It means that connection is not established between server and client before sending packets.
Type of communication i.e. TCP or UDP is specified in step no. 2 i.e. type is SOCK_STREAM in TCP while it is SOCK_DGRAM in UDP.
For e.g. In UDP, we wrote:
sd = socket(AF_INET, SOCK_DGRAM, 0)
while creating a socket.
Client machine implements following steps:
1. Create a socket.
2. Assign family, type and port number to the created socket.
3. Connect the client's socket to server socket.
4. Send and receive messages till client types 'bye'
Since, UDP is connectionless protocol, step no. 3 is absent in UDP client code. While it is must in TCP client code.
Another difference between TCP and UDP socket programming is the functions used for sending and receiving packets(in this case, messages).
In TCP,
read(sd, buffer, sizeof(buffer));
While, in UDP,
recvlen = recvfrom(sd, buffer, BUFSIZE, 0, (struct sockaddr *)&rem_socket, &addrlen);
command used for reading.
We specify a socket address to receive packets in UDP since connection is not specified in advance.
In TCP,
write(sd, buffer, sizeof(buffer));
While in UDP,
sendto(sd, buffer, sizeof(buffer), 0, (struct sockaddr *)&rem_socket, addrlen);
In UDP, reply is sent via the socket received in read command. In this way, even if connection is not maintained, server can still reply to client's packets.