This article is for programmers with the following requirements:
Before you start learning socket programming, make sure you already have a certain basic knowledge of network such as understanding what is IP address, TCP, UDP.
Before we start our tutorial, keep in mind that the following tutorial only works for Linux OS environment. If you are using Windows, I have to apologize to you because Windows has its own socket programming and it is different from Linux even though the connection concept is the same. Well, first copy and paste the following code and run it on server and client, respectively.
Both codes can be run on the same computer.
It is always easy to understand after getting the code to work.
Socket-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 listenfd = 0,connfd = 0;
struct sockaddr_in serv_addr;
char sendBuff[1025];
int numrv;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
printf("socket retrieve success\n");
memset(&serv_addr, '0', sizeof(serv_addr));
memset(sendBuff, '0', sizeof(sendBuff));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(5000);
bind(listenfd, (struct sockaddr*)&serv_addr,sizeof(serv_addr));
if(listen(listenfd, 10) == -1){
printf("Failed to listen\n");
return -1;
}
while(1)
{
connfd = accept(listenfd, (struct sockaddr*)NULL ,NULL);
strcpy(sendBuff, "Message from server");
write(connfd, sendBuff, strlen(sendBuff));
close(connfd);
sleep(1);
}
return 0;
}
Socket-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>
int main(void)
{
int sockfd = 0,n = 0;
char recvBuff[1024];
struct sockaddr_in serv_addr;
memset(recvBuff, '0' ,sizeof(recvBuff));
if((sockfd = 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(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))<0)
{
printf("\n Error : Connect Failed \n");
return 1;
}
while((n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0)
{
recvBuff[n] = 0;
if(fputs(recvBuff, stdout) == EOF)
{
printf("\n Error : Fputs error");
}
printf("\n");
}
if( n < 0)
{
printf("\n Read Error \n");
}
return 0;
}
After debugging both source files, run Socket-server.out
, then run Socket-client
. Attention here, never mess up with the order of executing Socket-server.out
and Socket-client
. Socket-server
must be executed first, then execute Socket-client.out
and never try to break Socket-server
forever loop. It means, you need to open two terminals to run each of the outputs.
When you execute Socket-cli
, I guess you will get the following result:
If you see the message above, congratulations, you have success with your first step to networking programming. Otherwise, do some checking on your development environment or try to run some simple code for instance hello world.
Why Both Server and Client on the Same Computer?
The answer is the server and client both are software but not hardware. It means what is happening on the top is there are two different software executed. To be more precise, the server and client are two different processes with different jobs. If you are experienced with constructing a server, you might find out that a server can be built on a home computer by installing a server OS. It is because server is a kind of software.
Understand Sockets
Imagine a socket as a seaport that allows a ship to unload and gather shipping, whereas socket is the place where a computer gathers and puts data into the internet.
Configure Socket
Things that need to be initialized are listed as follows:
- Using TCP or UDP
- Additional protocol
- Permit the incoming IP address
- Assign the port used
At the beginning, a socket function needs to be declared to get the socket descriptor.
int socket(int domain, int type, int protocol)
Domain | AF_UNIX - connect inside same machine AF_INET – connect with different machine |
Type | SOCK_STREAM – TCP connection SOCK_DGRAM – UDP connection |
Protocol | Define here when there is any additional protocol. Otherwise, define it as 0 |
Next, decide which struct
needs to be used based on what domain is used above.
AF_UNIX | AF_INET |
struct sockaddr_un
{
sa_family_t sun_family ;
char sun_path[];
};
|
struct sockaddr_in
{
short int sin_family ;
int sin_port;
struct in_addr sin_addr;
};
|
Use struct sockaddr_un if you are using AF_UNIX on your domain. It is required to include <sys/un.h> | Use struct sockaddr_in if you are using AF_INT on your domain. |
In this article, I will explain sockadd_in
that showed in the code above.
serv_addr.sin_family = AF_INET;
| Define the domain used |
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
| Permit any incoming IP address by declaring INADDR_ANY |
serv_addr.sin_port = htons(5000);
| Declare port 5000 to be used. |
Based on the example above, server is using port 5000. You can check it by the following command:
sudo netstat -ntlp
Then, you will see the following list:
Inside red bracket, you will find 0.0.0.0:5000 and Socket-server
, it means port 5000 is used and listen to any valid incoming address.
On client side, serv_addr.sin_port = htons(127.0.0.1)
is declared in order to listen to the internal network.
The flow chart below shows the interaction between client and server. The flow chart might look complicated but make sure you don’t lose your patience due to the following flow chart. Because every process on the flow chart is needed and it acts as a very important role on network connection.
After all setup on struct sockaddr_in
is done, declare bind
function. As flow chart, bind
function must be declared on both server and client.
bind function
server_socket & client_socket | Put socket description retrieved on the top |
address | Put struct sockaddr_in into it as domain is AF_INET . If your domain is AF_UNIX , try and put struct sockaddr_un here. |
address_len | Put the length of the address |
Server and client will start interacting with each other after the bind
function and it is the most important session. From what flow chart shows, listen
, accept
, connect
, three functions play very important roles.
Imagine that server looks like an ATM, and only one person can be used the ATM. So, what happens if there are 2 or more people that come at one time? The answer is simple, lining up and wait for the front people to finish using with ATM. It is exactly the same as what is happening in the server.
Listen
function acts as a waiting room, asking the traffic wait on the waiting room. Accept
function acts as the person who is asking the traffic waiting inside the waiting room to be ready for the meeting between server. Last, connect
function acts as the person who wants to carry out some work with the server.
listen function
server_socket | Put socket description retrieved on the top |
backlog | Define the maximum of awaiting request |
accept function
server_socket | Put socket description retrieved on the top |
client_address | Put null here if there is no special request to specify address. |
address_len | Put null here if second parameter is null |
return | Return information of client socket description. Use it for interaction between client and server. |
connect function
client_socket | Put socket description retrieved on the top |
address | Put the struct sockaddr defined on the top |
address_len | Put the length of the address |
Finally, after the request is accepted, what should server and client do is send and read data. It is the most simple part in this entire article. read
function is used to read the buffer data and write
function is used to send the data. That’s all.
read function
socket_description | Put server or client socket description depending on reading data from server or client |
read buffer | Content of the data retrieved |
read buffer length | Length of the output string |
write function
socket_description | Put server or client socket description depending on sending data to server or client |
write buffer | Data to be sent |
write buffer length | Length of the output string |
Personal Comment
This article was published on 2013/5/1 and I was still new to networking programming at that time. Maybe there is some point that I am not making clear enough. I have tried my best to present all my knowledge to this article. Hope you can get the good basic beginning over here. Thank you!