Sunteți pe pagina 1din 34

C Socket Programming for Linux

with a Server and Client Example


Code
by Himanshu Arora on December 19, 2011
Object 1

Object 3

Object 2

Typically two processes communicate with each other on a single system through one of the
following inter process communication techniques.
Pipes
Message queues
Shared memory
There are several other methods. But the above are some of the very classic ways of interprocess
communication.
But have you ever given a thought over how two processes communicate across a network?
For example, when you browse a website, on your local system the process running is your web
browser, while on the remote system the process running is the web server. So this is also an inter
process communication but the technique through which they communicate with each other is
SOCKETS, which is the focus of this article.

What is a SOCKET?
In laymans term, a Socket is an end point of communication between two systems on a network. To
be a bit precise, a socket is a combination of IP address and port on one system. So on each system
a socket exists for a process interacting with the socket on other system over the network. A
combination of local socket and the socket at the remote system is also known a Four tuple or 4tuple. Each connection between two processes running at different systems can be uniquely
identified through their 4-tuple.
There are two types of network communication models:
1. OSI
2. TCP/IP
While OSI is more of a theoretical model, the TCP/IP networking model is the most popular and
widely used.
As explained in our TCP/IP Fundamentals article, the communication over the network in TCP/IP
model takes place in form of a client server architecture. ie, the client begins the communication
and server follows up and a connection is established.
Sockets can be used in many languages like Java, C++ etc but here in this article, we will
understand the socket communication in its purest form (i.e in C programming language)

Lets create a server that continuously runs and sends the date and time as soon as a client connects
to it.

Socket Server Example


#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

<sys/socket.h>
<netinet/in.h>
<arpa/inet.h>
<stdio.h>
<stdlib.h>
<unistd.h>
<errno.h>
<string.h>
<sys/types.h>
<time.h>

int main(int argc, char *argv[])


{
int listenfd = 0, connfd = 0;
struct sockaddr_in serv_addr;
char sendBuff[1025];
time_t ticks;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
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));
listen(listenfd, 10);
while(1)
{
connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);
ticks = time(NULL);
snprintf(sendBuff, sizeof(sendBuff), "%.24s\r\n", ctime(&ticks));
write(connfd, sendBuff, strlen(sendBuff));

close(connfd);
sleep(1);

In the above program, we have created a server. In the code :


The call to the function socket() creates an UN-named socket inside the kernel and returns
an integer known as socket descriptor.
This function takes domain/family as its first argument. For Internet family of IPv4
addresses we use AF_INET.
The second argument SOCK_STREAM specifies that the transport layer protocol that we
want should be reliable ie it should have acknowledgement techniques. For example : TCP
The third argument is generally left zero to let the kernel decide the default protocol to use

for this connection. For connection oriented reliable connections, the default protocol used is
TCP.
The call to the function bind() assigns the details specified in the structure serv_addr to
the socket created in the step above. The details include, the family/domain, the interface to
listen on(in case the system has multiple interfaces to network) and the port on which the
server will wait for the client requests to come.
The call to the function listen() with second argument as 10 specifies maximum number
of client connections that server will queue for this listening socket.
After the call to listen(), this socket becomes a fully functional listening socket.
In the call to accept(), the server is put to sleep and when for an incoming client request, the
three way TCP handshake* is complete, the function accept () wakes up and returns the
socket descriptor representing the client socket.
The call to accept() is run in an infinite loop so that the server is always running and the
delay or sleep of 1 sec ensures that this server does not eat up all of your CPU processing.
As soon as server gets a request from client, it prepares the date and time and writes on the
client socket through the descriptor returned by accept().

Three way handshake is the procedure that is followed to establish a TCP connection between two
remote hosts. We might soon be posting an article on the theoretical aspect of the TCP protocol.
Finally, we compile the code and run the server.

Socket Client Example


#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

<sys/socket.h>
<sys/types.h>
<netinet/in.h>
<netdb.h>
<stdio.h>
<string.h>
<stdlib.h>
<unistd.h>
<errno.h>
<arpa/inet.h>

int main(int argc, char *argv[])


{
int sockfd = 0, n = 0;
char recvBuff[1024];
struct sockaddr_in serv_addr;
if(argc != 2)
{
printf("\n Usage: %s <ip of server> \n",argv[0]);
return 1;
}
memset(recvBuff, '0',sizeof(recvBuff));
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("\n Error : Could not create socket \n");
return 1;
}
memset(&serv_addr, '0', sizeof(serv_addr));

serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(5000);
if(inet_pton(AF_INET, argv[1], &serv_addr.sin_addr)<=0)
{
printf("\n inet_pton error occured\n");
return 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\n");
}
}
if(n < 0)
{
printf("\n Read error \n");
}
}

return 0;

In the above program, we create a client which will connect to the server and receive date and time
from it. In the above piece of code :
We see that here also, a socket is created through call to socket() function.
Information like IP address of the remote host and its port is bundled up in a structure and a
call to function connect() is made which tries to connect this socket with the socket (IP
address and port) of the remote host.
Note that here we have not bind our client socket on a particular port as client generally use
port assigned by kernel as client can have its socket associated with any port but In case of
server it has to be a well known socket, so known servers bind to a specific port like HTTP
server runs on port 80 etc while there is no such restrictions on clients.
Once the sockets are connected, the server sends the data (date+time) on clients socket
through clients socket descriptor and client can read it through normal read call on the its
socket descriptor.
Now execute the client as shown below.
$ ./newsc 127.0.0.1
Sun Dec 18 22:22:14 2011

We can see that we successfully got the date and time from server. We need to send the IP address
of the server as an argument for this example to run. If you are running both server and client
example on the same machine for testing purpose, use the loop back ip address as shown above.

To conclude, In this article we studied the basics of socket programming through a live example
that demonstrated communication between a client and server processes capable of running on two
different machines.

Finally, to test the code you just need to run the server on a terminal and then
run the client on a different terminal (or run the server as a background
process and then run the client on the same terminal).
****************** SERVER CODE ****************/
#include
#include
#include
#include

<stdio.h>
<sys/socket.h>
<netinet/in.h>
<string.h>

int main(){
int welcomeSocket, newSocket;
char buffer[1024];
struct sockaddr_in serverAddr;
struct sockaddr_storage serverStorage;
socklen_t addr_size;
/*---- Create the socket. The three arguments are: ----*/
/* 1) Internet domain 2) Stream socket 3) Default protocol (TCP in this case)
*/

welcomeSocket = socket(PF_INET, SOCK_STREAM, 0);


/*---- Configure settings of the server address struct ----*/
/* Address family = Internet */
serverAddr.sin_family = AF_INET;
/* Set port number, using htons function to use proper byte order */
serverAddr.sin_port = htons(7891);
/* Set IP address to localhost */
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
/* Set all bits of the padding field to 0 */
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
/*---- Bind the address struct to the socket ----*/
bind(welcomeSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr));
/*---- Listen on the socket, with 5 max connection requests queued ----*/
if(listen(welcomeSocket,5)==0)
printf("Listening\n");
else
printf("Error\n");

/*---- Accept call creates a new socket for the incoming connection ----*/
addr_size = sizeof serverStorage;
newSocket = accept(welcomeSocket, (struct sockaddr *) &serverStorage,
&addr_size);
/*---- Send message to the socket of the incoming connection ----*/
strcpy(buffer,"Hello World\n");
send(newSocket,buffer,13,0);
return 0;
}

Client Code
/****************** CLIENT CODE ****************/
#include
#include
#include
#include

<stdio.h>
<sys/socket.h>
<netinet/in.h>
<string.h>

int main(){
int clientSocket;
char buffer[1024];
struct sockaddr_in serverAddr;
socklen_t addr_size;
/*---- Create the socket. The three arguments are: ----*/
/* 1) Internet domain 2) Stream socket 3) Default protocol (TCP in this case)

*/

clientSocket = socket(PF_INET, SOCK_STREAM, 0);


/*---- Configure settings of the server address struct ----*/
/* Address family = Internet */
serverAddr.sin_family = AF_INET;
/* Set port number, using htons function to use proper byte order */
serverAddr.sin_port = htons(7891);
/* Set IP address to localhost */
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
/* Set all bits of the padding field to 0 */
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
/*---- Connect the socket to the server using the address struct ----*/
addr_size = sizeof serverAddr;
connect(clientSocket, (struct sockaddr *) &serverAddr, addr_size);
/*---- Read the message from the server into the buffer ----*/
recv(clientSocket, buffer, 1024, 0);
/*---- Print the received message ----*/
printf("Data received: %s",buffer);
}

return 0;

TCP/IP socket programming in C


This is a quick tutorial on socket programming in c language on a Linux system. "Linux" because
the code snippets shown over here will work only on a Linux system and not on Windows. The
windows api to socket programming is called winsock and we shall go through it in another tutorial.

Sockets are the "virtual" endpoints of any kind of network communications done between 2 hosts

over in a network. For example when you type www.google.com in your web browser, it opens a
socket and connects to google.com to fetch the page and show it to you. Same with any chat client
like gtalk or skype. Any network communication goes through a socket.
The socket api on linux is similar to bsd/unix sockets from which it has evolved. Although over
time the api has become slightly different at few places. And now the newer official standard is
posix sockets api which is same as bsd sockets.
This tutorial assumes that you have basic knowledge of C and pointers. You will need to have gcc
compiler installed on your Linux system. An IDE along with gcc would be great. I would
recommend geany as you can quickly edit and run single file programs in it without much
configurations. On ubuntu you can do a sudo apt-get install geany on the terminal.
All along the tutorial there are code snippets to demonstrate some concepts. You can run those code
snippets in geany rightaway and test the results to better understand the concepts.

Create a socket
This first thing to do is create a socket. The socket function does this.
Here is a code sample :
1 #include<stdio.h>
2 #include<sys/socket.h>
3
4 int main(int argc , char *argv[])
5 {
int socket_desc;
6
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
7
8
9
if (socket_desc == -1)
{
10
printf("Could not create socket");
11
}
12
13
14
return 0;
15 }
Function socket() creates a socket and returns a descriptor which can be used in other functions.
The above code will create a socket with following properties
Address Family - AF_INET (this is IP version 4)
Type - SOCK_STREAM (this means connection oriented TCP protocol)
Protocol - 0 [ or IPPROTO_IP This is IP protocol]

Next we shall try to connect to some server using this socket.


We can connect to www.google.com
Note
Apart from SOCK_STREAM type of sockets there is another type called SOCK_DGRAM which
indicates the UDP protocol. This type of socket is non-connection socket. In this tutorial we shall

stick to SOCK_STREAM or TCP sockets.

Connect socket to a server


We connect to a remote server on a certain port number. So we need 2 things, ip address and port
number to connect to.
To connect to a remote server we need to do a couple of things. First is to create a sockaddr_in
structure with proper values.
struct sockaddr_in server;

Have a look at the structure


1 // IPv4 AF_INET sockets:
2 struct sockaddr_in {
short
sin_family;
// e.g. AF_INET, AF_INET6
3
unsigned
short
sin_port;
// e.g. htons(3490)
4
struct in_addr
sin_addr;
// see struct in_addr, below
5
char
sin_zero[8]; // zero this if you want to
6
7 };
8
9 struct in_addr {
10
unsigned long s_addr;
// load with inet_pton()
11 };
12
13 struct sockaddr {
14
unsigned short sa_family;
// address family, AF_xxx
15
char
sa_data[14]; // 14 bytes of protocol address
16 };
The sockaddr_in has a member called sin_addr of type in_addr which has a s_addr which is nothing
but a long. It contains the IP address in long format.
Function inet_addr is a very handy function to convert an IP address to a long format. This is
how you do it :
1 server.sin_addr.s_addr = inet_addr("74.125.235.20");
So you need to know the IP address of the remote server you are connecting to. Here we used the ip
address of google.com as a sample. A little later on we shall see how to find out the ip address of a
given domain name.
The last thing needed is the connect function. It needs a socket and a sockaddr structure to
connect to. Here is a code sample.

#include<stdio.h>
1 #include<sys/socket.h>
2 #include<arpa/inet.h> //inet_addr
3
4 int main(int argc , char *argv[])
5 {
6
int socket_desc;
7
struct sockaddr_in server;
8
9
//Create socket
10
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
11
if (socket_desc == -1)
12
{
13
printf("Could not create socket");
14
}
15
16
server.sin_addr.s_addr = inet_addr("74.125.235.20");
17
server.sin_family = AF_INET;
18
server.sin_port = htons( 80 );
19
20
//Connect to remote server
21
if (connect(socket_desc , (struct sockaddr *)&server ,
22
sizeof(server)) < 0)
23
{
24
puts("connect error");
25
return 1;
26
}
27
28
puts("Connected");
29
return 0;
30
}
It cannot be any simpler. It creates a socket and then connects. If you run the program it should
show Connected.
Try connecting to a port different from port 80 and you should not be able to connect which
indicates that the port is not open for connection.
OK , so we are now connected. Lets do the next thing , sending some data to the remote server.
Connections are present only in tcp sockets
The concept of "connections" apply to SOCK_STREAM/TCP type of sockets. Connection means a
reliable "stream" of data such that there can be multiple such streams each having communication
of its own. Think of this as a pipe which is not interfered by other data.
Other sockets like UDP , ICMP , ARP dont have a concept of "connection". These are nonconnection based communication. Which means you keep sending or receiving packets from
anybody and everybody.

Send data over socket


Function send will simply send data. It needs the socket descriptor , the data to send and its size.
Here is a very simple example of sending some data to google.com ip :

#include<stdio.h>
1 #include<string.h>
//strlen
2 #include<sys/socket.h>
3 #include<arpa/inet.h> //inet_addr
4
5 int main(int argc , char *argv[])
6 {
7
int socket_desc;
8
struct sockaddr_in server;
9
char *message;
10
11
//Create socket
12
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
13
if (socket_desc == -1)
14
{
15
printf("Could not create socket");
16
}
17
18
server.sin_addr.s_addr = inet_addr("74.125.235.20");
19
server.sin_family = AF_INET;
20
server.sin_port = htons( 80 );
21
22
//Connect to remote server
23
if (connect(socket_desc , (struct sockaddr *)&server ,
24
sizeof(server)) < 0)
25
{
26
puts("connect error");
27
return 1;
28
}
29
30
puts("Connected\n");
31
32
//Send some data
33
message = "GET / HTTP/1.1\r\n\r\n";
34
if( send(socket_desc , message , strlen(message) , 0) < 0)
35
{
36
puts("Send failed");
37
return 1;
38
}
39
puts("Data Send\n");
40
41
return 0;
42
}
In the above example , we first connect to an ip address and then send the string message "GET /
HTTP/1.1\r\n\r\n" to it.
The message is actually a http command to fetch the mainpage of a website.
Now that we have send some data , its time to receive a reply from the server. So lets do it.
Note
When sending data to a socket you are basically writing data to that socket. This is similar to

writing data to a file. Hence you can also use the write function to send data to a socket. Later in
this tutorial we shall use write function to send data.

Receive data on socket


Function recv is used to receive data on a socket. In the following example we shall send the same
message as the last example and receive a reply from the server.

#include<stdio.h>
1 #include<string.h>
//strlen
2 #include<sys/socket.h>
3 #include<arpa/inet.h> //inet_addr
4
5 int main(int argc , char *argv[])
6 {
7
int socket_desc;
8
struct sockaddr_in server;
9
char *message , server_reply[2000];
10
11
//Create socket
12
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
13
if (socket_desc == -1)
14
{
15
printf("Could not create socket");
16
}
17
18
server.sin_addr.s_addr = inet_addr("74.125.235.20");
19
server.sin_family = AF_INET;
20
server.sin_port = htons( 80 );
21
22
//Connect to remote server
23
if (connect(socket_desc , (struct sockaddr *)&server ,
24
sizeof(server)) < 0)
25
{
26
puts("connect error");
27
return 1;
28
}
29
30
puts("Connected\n");
31
32
//Send some data
33
message = "GET / HTTP/1.1\r\n\r\n";
34
if( send(socket_desc , message , strlen(message) , 0) < 0)
35
{
36
puts("Send failed");
37
return 1;
38
}
39
puts("Data Send\n");
40
41
//Receive a reply from the server
42
if( recv(socket_desc, server_reply , 2000 , 0) < 0)
43
{
44
puts("recv failed");
45
}
46
puts("Reply received\n");
47
puts(server_reply);
48
49
return 0;
50
}
Here is the output of the above code :

Connected
Data Send
Reply received
HTTP/1.1 302 Found
Location: http://www.google.co.in/
Cache-Control: private
Content-Type: text/html; charset=UTF-8
Set-Cookie:
PREF=ID=0edd21a16f0db219:FF=0:TM=1324644706:LM=1324644706:S=z6hDC9cZfGEowv_o;
expires=Sun, 22-Dec-2013 12:51:46 GMT; path=/; domain=.google.com
Date: Fri, 23 Dec 2011 12:51:46 GMT
Server: gws
Content-Length: 221
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
<A HREF="http://www.google.co.in/">here</A>.
</BODY></HTML>

We can see what reply was send by the server. It looks something like Html, well IT IS html.
Google.com replied with the content of the page we requested. Quite simple!
Note
When receiving data on a socket , we are basically reading the data on the socket. This is similar to
reading data from a file. So we can also use the read function to read data on a socket. For
example :
1 read(socket_desc, server_reply , 2000);
Now that we have received our reply, its time to close the socket.

Close socket
Function close is used to close the socket. Need to include the unistd.h header file for this.
1 close(socket_desc);
Thats it.

Summary
So in the above example we learned how to
1.
2.
3.
4.

Create a socket
Connect to remote server
Send some data
Receive a reply

Your web browser also does the same thing when you open www.google.com
This kind of socket activity represents a socket client. A client is an application that connects to a
remote system to fetch or retrieve data.

The other kind of socket application is called a socket server. A server is a system that uses sockets
to receive incoming connections and provide them with data. It is just the opposite of Client. So
www.google.com is a server and your web browser is a client. Or more technically
www.google.com is a HTTP Server and your web browser is an HTTP client.
Now its time to do some server tasks using sockets. But before we move ahead there are a few side
topics that should be covered just incase you need them.

Get ip address of hostname


When connecting to a remote host , it is necessary to have its IP address. Function
gethostbyname is used for this purpose. It takes the domain name as the parameter and returns a
structure of type hostent. This structure has the ip information. It is present in netdb.h. Lets have
a look at this structure
/* Description of data base entry for a single host. */
1 struct hostent
2{
3 char *h_name;
/* Official name of host. */
4 char **h_aliases;
/* Alias list. */
5
int h_addrtype;
/* Host address type. */
6
/* Length of address. */
7 int h_length;
char
**h_addr_list;
/* List of addresses from name
8
9 server. */
};
The h_addr_list has the IP addresses. So now lets have some code to use them.

#include<stdio.h> //printf
#include<string.h> //strcpy
#include<sys/socket.h>
#include<netdb.h> //hostent
#include<arpa/inet.h>

1
2
3
4
5
6 int main(int argc , char *argv[])
7 {
8
char *hostname = "www.google.com";
9
char ip[100];
10
struct hostent *he;
11
struct in_addr **addr_list;
12
int i;
13
14
if ( (he = gethostbyname( hostname ) ) == NULL)
15
{
16
//gethostbyname failed
17
herror("gethostbyname");
18
return 1;
19
}
20
21
//Cast the h_addr_list to in_addr , since h_addr_list also
22
has
the ip address in long format only
23
addr_list = (struct in_addr **) he->h_addr_list;
24
25
for(i = 0; addr_list[i] != NULL; i++)
26
{
27
//Return the first one;
28
strcpy(ip , inet_ntoa(*addr_list[i]) );
29
}
30
31
printf("%s resolved to : %s" , hostname , ip);
32
return 0;
33
}
Output of the code would look like :
www.google.com resolved to : 74.125.235.20

So the above code can be used to find the ip address of any domain name. Then the ip address can
be used to make a connection using a socket.
Function inet_ntoa will convert an IP address in long format to dotted format. This is just the
opposite of inet_addr.
So far we have see some important structures that are used. Lets revise them :
1. sockaddr_in - Connection information. Used by connect , send , recv etc.
2. in_addr - Ip address in long format
3. sockaddr
4. hostent - The ip addresses of a hostname. Used by gethostbyname
In the next part we shall look into creating servers using socket. Servers are the opposite of clients,

that instead of connecting out to others, they wait for incoming connections.

Socket server
OK now onto server things. Socket servers operate in the following manner
1.
2.
3.
4.
5.

Open a socket
Bind to a address(and port).
Listen for incoming connections.
Accept connections
Read/Send

We have already learnt how to open a socket. So the next thing would be to bind it.

Bind socket to a port


The bind function can be used to bind a socket to a particular "address and port" combination. It
needs a sockaddr_in structure similar to connect function.
int socket_desc;
1 struct sockaddr_in server;
2
3
//Create socket
4
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
5
if (socket_desc == -1)
6
{
7
printf("Could not create socket");
8
}
9
10
//Prepare the sockaddr_in structure
11
server.sin_family = AF_INET;
12
server.sin_addr.s_addr = INADDR_ANY;
13
server.sin_port = htons( 8888 );
14
15
16 //Bind
17 if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server))
18 < 0)
19 {
puts("bind failed");
20
}
21
puts("bind done");
Now that bind is done, its time to make the socket listen to connections. We bind a socket to a
particular IP address and a certain port number. By doing this we ensure that all incoming data
which is directed towards this port number is received by this application.
This makes it obvious that you cannot have 2 sockets bound to the same port.

Listen for incoming connections on the socket


After binding a socket to a port the next thing we need to do is listen for connections. For this we
need to put the socket in listening mode. Function listen is used to put the socket in listening
mode. Just add the following line after bind.

1 //Listen
2 listen(socket_desc , 3);
Thats all. Now comes the main part of accepting new connections.

Accept connection
Function accept is used for this. Here is the code
1 #include<stdio.h>
2 #include<sys/socket.h>
3 #include<arpa/inet.h> //inet_addr
4
5 int main(int argc , char *argv[])
6 {
7
int socket_desc , new_socket , c;
8
struct sockaddr_in server , client;
9
10
//Create socket
11
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
12
if (socket_desc == -1)
13
{
14
printf("Could not create socket");
15
}
16
17
//Prepare the sockaddr_in structure
18
server.sin_family = AF_INET;
19
server.sin_addr.s_addr = INADDR_ANY;
20
server.sin_port = htons( 8888 );
21
22
//Bind
23
if( bind(socket_desc,(struct sockaddr *)&server ,
24 sizeof(server)) < 0)
25
{
26
puts("bind failed");
27
}
28
puts("bind done");
29
30
//Listen
31
listen(socket_desc , 3);
32
33
//Accept and incoming connection
34
puts("Waiting for incoming connections...");
35
c = sizeof(struct sockaddr_in);
36
new_socket = accept(socket_desc, (struct sockaddr *)&client,
37
(socklen_t*)&c);
38
if (new_socket<0)
39
{
40
perror("accept failed");
41
}
42
43
puts("Connection accepted");
44

return 0;
}
Program output
Run the program. It should show
bind done
Waiting for incoming connections...

So now this program is waiting for incoming connections on port 8888. Dont close this program ,
keep it running.
Now a client can connect to it on this port. We shall use the telnet client for testing this. Open a
terminal and type
$ telnet localhost 8888

On the terminal you shall get


Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Connection closed by foreign host.

And the server output will show


bind done
Waiting for incoming connections...
Connection accepted

So we can see that the client connected to the server. Try the above process till you get it perfect.
Get the ip address of the connected client
You can get the ip address of client and the port of connection by using the sockaddr_in structure
passed to accept function. It is very simple :
1 char *client_ip = inet_ntoa(client.sin_addr);
2 int client_port = ntohs(client.sin_port);
We accepted an incoming connection but closed it immediately. This was not very productive.
There are lots of things that can be done after an incoming connection is established. Afterall the
connection was established for the purpose of communication. So lets reply to the client.
We can simply use the write function to write something to the socket of the incoming connection
and the client should see it. Here is an example :

1 #include<stdio.h>
//strlen
2 #include<string.h>
3 #include<sys/socket.h>
4 #include<arpa/inet.h> //inet_addr
//write
5 #include<unistd.h>
6
7 int main(int argc , char *argv[])
8 {
int socket_desc , new_socket , c;
9
10
struct sockaddr_in server , client;
11
char *message;
12
13
//Create socket
14
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
15
if (socket_desc == -1)
16
{
17
printf("Could not create socket");
18
}
19
20
//Prepare the sockaddr_in structure
21
server.sin_family = AF_INET;
22
server.sin_addr.s_addr = INADDR_ANY;
23
server.sin_port = htons( 8888 );
24
25
//Bind
26
if( bind(socket_desc,(struct sockaddr *)&server ,
27 sizeof(server)) < 0)
28
{
29
puts("bind failed");
30
return 1;
31
}
32
puts("bind done");
33
34
//Listen
35
listen(socket_desc , 3);
36
37
//Accept and incoming connection
38
puts("Waiting for incoming connections...");
39
c = sizeof(struct sockaddr_in);
40
new_socket = accept(socket_desc, (struct sockaddr *)&client,
41
(socklen_t*)&c);
42
if (new_socket<0)
43
{
44
perror("accept failed");
45
return 1;
46
}
47
48
puts("Connection accepted");
49
50
//Reply to the client
51
message = "Hello Client , I have received your connection.
52

But I have to go now, bye\n";


write(new_socket , message , strlen(message));
53
return 0;
}
Run the above code in 1 terminal. And connect to this server using telnet from another terminal and
you should see this :
$ telnet localhost 8888
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hello Client , I have received your connection. But I have to go now, bye
Connection closed by foreign host.

So the client(telnet) received a reply from server.


We can see that the connection is closed immediately after that simply because the server program
ends after accepting and sending reply. A server like www.google.com is always up to accept
incoming connections.
It means that a server is supposed to be running all the time. Afterall its a server meant to serve. So
we need to keep our server RUNNING non-stop. The simplest way to do this is to put the accept
in a loop so that it can receive incoming connections all the time.

Live Server
So a live server will be alive for all time. Lets code this up :

#include<stdio.h>
#include<string.h>
//strlen
1 #include<sys/socket.h>
2 #include<arpa/inet.h> //inet_addr
//write
3 #include<unistd.h>
4
5 int main(int argc , char *argv[])
6 {
7
int socket_desc , new_socket , c;
8
struct sockaddr_in server , client;
9
char *message;
10
11
//Create socket
12
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
13
if (socket_desc == -1)
14
{
15
printf("Could not create socket");
16
}
17
18
//Prepare the sockaddr_in structure
19
server.sin_family = AF_INET;
20
server.sin_addr.s_addr = INADDR_ANY;
21
server.sin_port = htons( 8888 );
22
23
//Bind
24
if( bind(socket_desc,(struct sockaddr *)&server ,
25 sizeof(server)) < 0)
26
{
27
puts("bind failed");
28
return 1;
29
}
30
puts("bind done");
31
32
//Listen
33
listen(socket_desc , 3);
34
35
//Accept and incoming connection
36
puts("Waiting for incoming connections...");
37
c = sizeof(struct sockaddr_in);
38
while( (new_socket = accept(socket_desc, (struct sockaddr
39
*)&client,
(socklen_t*)&c)) )
40
{
41
puts("Connection accepted");
42
43
//Reply to the client
44
message = "Hello Client , I have received your
45
connection.
But I have to go now, bye\n";
46
write(new_socket , message , strlen(message));
47
}
48
49
if (new_socket<0)
50
{
51
perror("accept failed");

We havent done a lot there. Just the accept was put in a loop.
Now run the program in 1 terminal , and open 3 other terminals. From each of the 3 terminal do a
telnet to the server port.
Each of the telnet terminal would show :
$ telnet localhost 8888
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hello Client , I have received your connection. But I have to go now, bye

And the server terminal would show


bind done
Waiting for incoming connections...
Connection accepted
Connection accepted
Connection accepted

So now the server is running nonstop and the telnet terminals are also connected nonstop. Now
close the server program.
All telnet terminals would show "Connection closed by foreign host."
Good so far. But still there is not effective communication between the server and the client.
The server program accepts connections in a loop and just send them a reply, after that it does
nothing with them. Also it is not able to handle more than 1 connection at a time. So now its time to
handle the connections , and handle multiple connections together.

Handle multiple socket connections with threads


To handle every connection we need a separate handling code to run along with the main server
accepting connections.
One way to achieve this is using threads. The main server program accepts a connection and creates
a new thread to handle communication for the connection, and then the server goes back to accept
more connections.
On Linux threading can be done with the pthread (posix threads) library. It would be good to read
some small tutorial about it if you dont know anything about it. However the usage is not very
complicated.
We shall now use threads to create handlers for each connection the server accepts. Lets do it pal.

#include<stdio.h>
#include<string.h>
//strlen
#include<stdlib.h>
//strlen
#include<sys/socket.h>
1
2 #include<arpa/inet.h> //inet_addr
//write
3 #include<unistd.h>
4
#include<pthread.h> //for threading , link with lpthread
5
6
7 void *connection_handler(void *);
8
9 int main(int argc , char *argv[])
10 {
int socket_desc , new_socket , c , *new_sock;
11
struct sockaddr_in server , client;
12
char *message;
13
14
//Create socket
15
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
16
17
if (socket_desc == -1)
18
{
printf("Could not create socket");
19
}
20
21
22
//Prepare the sockaddr_in structure
23
server.sin_family = AF_INET;
24
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8888 );
25
26
27
//Bind
28
if( bind(socket_desc,(struct sockaddr *)&server ,
29 sizeof(server)) < 0)
30
{
31
puts("bind failed");
32
return 1;
33
}
34
puts("bind done");
35
36
//Listen
37
listen(socket_desc , 3);
38
39
//Accept and incoming connection
40
puts("Waiting for incoming connections...");
41
c = sizeof(struct sockaddr_in);
42
while( (new_socket = accept(socket_desc, (struct sockaddr
43 *)&client, (socklen_t*)&c)) )
44
{
45
puts("Connection accepted");
46
47
//Reply to the client
48
message = "Hello Client , I have received your
49 connection. And now I will assign a handler for you\n";
50
write(new_socket , message , strlen(message));

Run the above server and open 3 terminals like before. Now the server will create a thread for each
client connecting to it.
The telnet terminals would show :
$ telnet localhost 8888
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hello Client , I have received your connection. And now I will assign a handler
for you
Hello I am your connection handler
Its my duty to communicate with you

This one looks good , but the communication handler is also quite dumb. After the greeting it
terminates. It should stay alive and keep communicating with the client.
One way to do this is by making the connection handler wait for some message from a client as
long as the client is connected. If the client disconnects , the connection handler ends.
So the connection handler can be rewritten like this :

/*
* This will handle connection for each client
* */
void *connection_handler(void *socket_desc)
{
//Get the socket descriptor
int sock = *(int*)socket_desc;
int read_size;
char *message , client_message[2000];

1
2
3
4
5
6
7
8
9
//Send some messages to the client
10
message = "Greetings! I am your connection handler\n";
11
write(sock , message , strlen(message));
12
13
14
message = "Now type something and i shall repeat what you
15 type \n";
write(sock , message , strlen(message));
16
17
18
//Receive a message from client
19
while( (read_size = recv(sock , client_message , 2000 , 0)) >
20 0 )
{
21
//Send the message back to client
22
write(sock , client_message , strlen(client_message));
23
}
24
25
26
if(read_size == 0)
{
27
puts("Client disconnected");
28
fflush(stdout);
29
}
30
31
else if(read_size == -1)
32
{
perror("recv failed");
33
}
34
35
36
//Free the socket pointer
37
free(socket_desc);
38
39
return 0;
}
The above connection handler takes some input from the client and replies back with the same.
Simple! Here is how the telnet output might look
$ telnet localhost 8888
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hello Client , I have received your connection. And now I will assign a handler
for you
Greetings! I am your connection handler
Now type something and i shall repeat what you type
Hello
Hello

How are you


How are you
I am fine
I am fine

So now we have a server thats communicative. Thats useful now.


Linking the pthread library
When compiling programs that use the pthread library you need to link the library. This is done like
this :
$ gcc program.c -lpthread

Conclusion
By now you must have learned the basics of socket programming in C. You can try out some
experiments like writing a chat client or something similar.
If you think that the tutorial needs some addons or improvements or any of the code snippets above
dont work then feel free to make a comment below so that it gets fixed.

UDP made simple


Abstract: This page describes how to write a simple UDP client/server system in a C/Unix
environment. The code is explained step by step.
Motivation: I needed a page like this when working with a small test program for my master's
thesis at Appius / Flt Communications. It is quite hard to remember all the socket API details off
the top of your head, so I wanted a small reference page to get me started quickly without having to
wade through tons of man pages. As I did not find a page I liked, I decided to write one. I hope it
will be useful for others, too.
Caveats: The code is known to work under recent (fall 1999) versions of Linux. It should work on
other Unices too, though some of the header files may be located in other directories on your
system.

The server
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

#include
#include
#include
#include
#include
#include

<arpa/inet.h>
<netinet/in.h>
<stdio.h>
<sys/types.h>
<sys/socket.h>
<unistd.h>

#define BUFLEN 512


#define NPACK 10
#define PORT 9930
void diep(char *s)
{
perror(s);
exit(1);

16 }
17
18 int main(void)
19 {
20
struct sockaddr_in si_me, si_other;
21
int s, i, slen=sizeof(si_other);
22
char buf[BUFLEN];
23
24
if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
25
diep("socket");
26
27
memset((char *) &si_me, 0, sizeof(si_me));
28
si_me.sin_family = AF_INET;
29
si_me.sin_port = htons(PORT);
30
si_me.sin_addr.s_addr = htonl(INADDR_ANY);
31
if (bind(s, &si_me, sizeof(si_me))==-1)
32
diep("bind");
33
34
for (i=0; i<NPACK; i++) {
35
if (recvfrom(s, buf, BUFLEN, 0, &si_other, &slen)==-1)
36
diep("recvfrom()");
37
printf("Received packet from %s:%d\nData: %s\n\n",
38
inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port), buf);
39
}
40
41
close(s);
42
return 0;
43 }

Comments
Lines 8-10 define the buffer size (quite arbitrary), the number of packets to receive and the
UDP port number to listen at. You could use any port number above 1023, although
bind() will fail if someone else is using the same port simultaneously.
The function diep() is used for error handling.
21: Declare receive buffer.
22: sockaddr_in is a structure containing an Internet socket address. Basically, it
contains:
an address family (always AF_INET for our purposes)
a port number
an IP address
si_me defines the socket where the server will listen. si_other defines the socket at the
other end of the link (that is, the client).
24: Create a socket. AF_INET says that it will be an Internet socket. SOCK_DGRAM says
that it will use datagram delivery instead of virtual circuits. IPPROTO_UDP says that it will
use the UDP protocol (the standard transport layer protocol for datagrams in IP networks).
Generally you can use zero for the last parameter; the kernel will figure out what protocol to
use (in this case, it would choose IPPROTO_UDP anyway).
27: We need to initialize the si_me structure. The first step is to fill it with binary zeroes,
which is done on this line. (I doubt this step is actually necessary in modern Unix
implementations, but better safe than sorry.)

28: We will use Internet addresses.


29: Here, the port number is defined. htons() ensures that the byte order is correct (Host
TO Network order/Short integer).
30: This line is used to tell what IP address we want to bind to. Most machines have more
than one network interface (for example, 127.0.0.1 for the loopback interface and some
other address for the network card; there may be more than one network card). In the general
case, you want to accept packets from any interface, so you use INADDR_ANY instead of a
specific address.
31: Now we are ready to bind the socket to the address we created above. This line tells the
system that the socket s should be bound to the address in si_me.
35: This call says that we want to receive a packet from s, that the data should be put info
buf, and that buf can store at most BUFLEN characters. The zero parameter says that no
special flags should be used. Data about the sender should be stored in si_other, which
has room for slen byte. Note that recvfrom() will set slen to the number of bytes
actually stored. If you want to play safe, set slen to sizeof(si_other) after each call
to recvfrom().
37: The information about the sender we got from recvfrom() is displayed (IP:port),
along with the data in the packet. inet_ntoa() takes a struct in_addr and converts
it to a string in dot notation, which is rather useful if you want to display the address in a
legible form.

The client
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

#define SRV_IP "999.999.999.999"


/* diep(), #includes and #defines like in the server */
int main(void)
{
struct sockaddr_in si_other;
int s, i, slen=sizeof(si_other);
char buf[BUFLEN];
if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
diep("socket");
memset((char *) &si_other, 0, sizeof(si_other));
si_other.sin_family = AF_INET;
si_other.sin_port = htons(PORT);
if (inet_aton(SRV_IP, &si_other.sin_addr)==0) {
fprintf(stderr, "inet_aton() failed\n");
exit(1);
}
for (i=0; i<NPACK; i++) {
printf("Sending packet %d\n", i);
sprintf(buf, "This is packet %d\n", i);
if (sendto(s, buf, BUFLEN, 0, &si_other, slen)==-1)
diep("sendto()");
}
close(s);
return 0;

30

Note: The client is quite similar to the server. Only the differences will be discussed.
1: You need to know the IP address of the machine where the server runs. If you run the
client and the server on the same machine, try 127.0.0.1. "999.999.999.999" is not a legal IP
address; you need to substitute your own server's address.
12: You may call bind() after the call to socket(), if you wish to specify which port
and interface that should be used for the client socket. However, this is almost never
necessary. The system will decide what port and interface to use.
13-19: Here, we set up a sockaddr_in corresponding to the socket address where the
server is listening. inet_aton() is used to convert a string in dotted-decimal ASCII
notation to a binary address.
24: Send BUFLEN bytes from buf to s, with no flags (0). The receiver is specified in
si_other, which contains slen byte.

General tips
Remember to always check return values from system calls! By doing so, you will save time
in the long run, I promise. Many people do not test return values in small quick-and-dirty
test programs. However, in such cases it is especially important to check return values,
because if you don't really know what you are doing you are much more likely to make a
mistake. The checks help you understand what went wrong and why.
There is a tool called netcat (the actual command is nc) which is very useful for testing
and debugging socket code. Check the man page if you are curious (of course, it might not
be installed on your system).
If you want to cut and paste the code above, use cut -c9- to get rid of the line numbers.
(The exact syntax of cut may be different on your system, and you may have to remove
more or less than 9 characters.)
The command netstat can be useful to check which sockets are active. Try netstat
-a.
For an overview over some of the structures used in socket programming, check out the code
examples from lecture 13 on my course in Unix system programming. You will also find
some material on TCP programming there. Disregard the initial material on select() and
friends. There are some comments in Swedish, but most of the page is written in C.

UDP Server Client Implementation


in C for Unix/Linux
Here's a simple UDP Server Client Implementation in C for Unix/Linux.
As UDP is a connection-less protocol, it is not reliable or we can say that we don't send
acknowledgements for the packets sent.
Here is a concurrent UDP server which can accept packets from multiple clients simultaneously.
The port mentioned here can be changed to any value between 1024 and 65535 (since upto 1024 are
known ports).
?

//UDPServer.c
1 /*
2 * gcc -o server UDPServer.c
3 * ./server
4 */
5 #include <arpa/inet.h>
6 #include <netinet/in.h>
7 #include <stdio.h>
8 #include <sys/types.h>
9 #include <sys/socket.h>
10 #include <unistd.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #define BUFLEN 512
14 #define PORT 9930
15
16 void err(char *str)
17 {
18
perror(str);
19
exit(1);
20 }
21
22 int main(void)
23 {
24
struct sockaddr_in my_addr, cli_addr;
25
int sockfd, i;
26
socklen_t slen=sizeof(cli_addr);
27
char buf[BUFLEN];
28
29
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
30
err("socket");
31
else
32
printf("Server : Socket() successful\n");
33
34
bzero(&my_addr, sizeof(my_addr));
35
my_addr.sin_family = AF_INET;
36
my_addr.sin_port = htons(PORT);
37
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
38
39
if (bind(sockfd, (struct sockaddr* ) &my_addr,
40
sizeof(my_addr))==-1)
41
err("bind");
42
else
43
printf("Server : bind() successful\n");
44
45
while(1)
46
{
47
if (recvfrom(sockfd, buf, BUFLEN, 0, (struct
48
sockaddr*)&cli_addr, &slen)==-1)
49
err("recvfrom()");
50
printf("Received packet from %s:%d\nData: %s\n\n",
51
inet_ntoa(cli_addr.sin_addr),
52

//UDPClient.c
1
2 /*
3 * gcc -o client UDPClient.c
4 * ./client <server-ip>
5 */
6
7 #include <arpa/inet.h>
8 #include <netinet/in.h>
9 #include <stdio.h>
10 #include <sys/types.h>
11 #include <sys/socket.h>
12 #include <unistd.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #define BUFLEN 512
16 #define PORT 9930
17
18 void err(char *s)
19 {
perror(s);
20
exit(1);
21
}
22
23
24 int main(int argc, char** argv)
25 {
struct sockaddr_in serv_addr;
26
int sockfd, i, slen=sizeof(serv_addr);
27
28
char buf[BUFLEN];
29
30
if(argc != 2)
{
31
printf("Usage : %s <Server-IP>\n",argv[0]);
32
exit(0);
33
}
34
35
36
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
37
err("socket");
38
bzero(&serv_addr, sizeof(serv_addr));
39
serv_addr.sin_family = AF_INET;
40
serv_addr.sin_port = htons(PORT);
41
42
if (inet_aton(argv[1], &serv_addr.sin_addr)==0)
43
{
44
fprintf(stderr, "inet_aton() failed\n");
exit(1);
45
}
46
47
while(1)
48
{
49
printf("\nEnter data to send(Type exit and press enter to
50
51 exit) : ");
scanf("%[^\n]",buf);
52

S-ar putea să vă placă și