Berkeley Sockets & TCP UDP Code
Berkeley Sockets & TCP UDP Code
TCP/IP stack
TCP layer
Chapter 6
The Transport Service
Services Provided to the Upper Layers
Transport Service Primitives
Berkeley Sockets
An Example of Socket Programming:
An Internet File Server
Services Provided to the Upper Layers
The network, transport, and application layers.
Attributes of TCP layer in TCP/IP
The entity which implements TCP functionality is
called TRANSPORT ENTITY. It talks to other similar
entity by sending a TPDU packet via IP layer.
It can be implemented in OS kernel, in network library
function, in a user space or in firmware of a Network
Interface Card.
It provides efficient, reliable and cost-effective service
to application layer.
It uses services provided by IP (lower) layer and does
not duplicate the same here.
Attributes of TCP layer in TCP/IP(2)
It provides CO and CL types of services primarily for
data-transfer. It also provides a method of directly
calling functions of IP layer.
It takes care of addressing, flow control and error-free
transportation between two end points.
TCP code runs mostly on host machines while lower 3
layers may run on switching equipment like routers and
link switches.
It covers all the short comings of network layer by
backing up or wrapping up it with its own superior
code.
Attributes of TCP layer in TCP/IP(3)
Suppose during a file transfer in a CO connection, the
failure occurs after half of records have been sent, TCP
may open extra connection and enquire which record
need to be resent, and send it and make up for loss.
Lost or mangled packets are compensated by TCP
layer code.
It hides a variety of networks in lower layers wireless
or wireline and thus to the application layer, it offers a
smooth seamless uniform experience.
Transport Service Primitives
The primitives for a simple hypothetical transport service.
LISTEN is for servers to create a socket and listen for clients arrival.
CONNECT is for client to make a connection request.
SEND, RECEIVE and DISCONNECT is for both client and server.
Transport Service Primitives (2)
The nesting of TPDUs, packets, and frames.
TPDU payload is message given by Application layer.
TCP adds TPDU header, IP adds Packet Header and Data Link adds
Frame Header to it send it to other machine.
Transport Service Primitives (3)
A state diagram for a simple connection management scheme.
Transitions labeled in italics are caused by packet arrivals. The
solid lines show the client's state sequence. The dashed lines show
the server's state sequence.
Transport Service Primitives (4)
Notes:
1. Initially both client and Server are in off state and they switch ON.
2. Server starts the process by executing LISTEN and blocks in IDLE state.
3. Client sends CONNECT TPDU and blocks in ACTIVE ESTABLISHMENT
PENDING state .
4. Server receives it, responds to it and enters PASSIVE ESTABLISHMENT
PENDING state and sends matching acknowledgement TPDU to client and
enters ESTABLISHED state. Client receives it and enters ESTABLISHED
state.
5. Both now SEND or RECEIVE data in both directions many times.
6. Disconnection can be initiated by any of the two. The one who initiates it
sends DISCONNECT TPDU and enters ACTIVE or PASSIVE DISCONNECT
PENDING STATE.
7. The receiver sends acknowledgement TPDU to initiator and enters IDLE
state. The initiator receives acknowledgement and enters IDLE state.
Berkeley Sockets
The socket primitives for TCP.
UNIX provided by UC Berkeley provided these service primitives or verbs or
functions in C at kernel level.
They offer more flexibility and facility than primitives we discussed.
we are going to write code to use them and our code will behave like
application layer programs.
First 4 primitives are used by server, fifth by only client and rest 3 by both.
Berkeley Sockets ..SOCKET primitive
This primitive is used by Server only.
This creates a new end point and allocates memory space for
creating Transport entity. It specifies parameters as:
Family: PF_INET (IPv4 type) or PF_INET6 (IPv6 type internet).
Type of socket: SOCK_STREAM for TCP, SOCK_DGRAM (for
UDP), SOCK_SeqPACKET for STCP, SOCK_RAW (for services
using IP services directly).
Protocol: Set to 0 since this is only one protocol at this layer.
Local Socket Address: Data Structure containing fields- local host
port no (process) , local host IP address and family ( AF_INET).
Remote Socket Address: Same as above except that it is for remote
host.
Berkeley Sockets ..SOCKET primitive
When this call is successful it returns a File Descriptor
(fd1) or socket id which is of type integer. This will be
used in all future socket commands as an identifier or
address to which each primitive command will be
directed. When a socket is closed, this identifier
perishes.
In newly created socket, the address fields are empty.
These will be filled up with server or client addresses at
appropriate time.
Berkeley Sockets ..BIND primitive
This primitives assigns server addresses to socket to
which remote clients will connect to.
Client addresses are not yet known since client has not
arrived yet so its identity is not known.
SOCKET and BIND create a first level socket
popularly called as listen socket. This socket will listen
to arrival of client requests. This will not be used for
data transfer.
It returns 0 as success and -1 as failure.
Berkeley Sockets ..LISTEN primitive
This primitives allocates queue space in memory
for remote hosts or clients to queue up to be
serviced. It also starts server process to check
and accept client requests.
If the queue size specified is 1 then first client
will be connected. While first client is
interacting with server, if second client attempts
to make a connection, it will fail.
Berkeley Sockets ..LISTEN primitive (2)
If the queue length specified is more than 1 then
second client will be put in a queue and will
block pending connection.
The server does not blocks on this call until a
client requests a connection. Blocking will come
later with next primitive.
We need to call this primitive often to empty the
queue.
It returns 0 as success and -1 as failure.
Berkeley Sockets ..ACCEPT primitive
This primitive causes server to block waiting for a
connection request to arrive from client.
Once the connection request TDPU from a client
arrives, server unblocks, creates a new socket with
same properties and new identifier and returns that as a
new file descriptor say fd2 which will be used for
read/write operations with the first client.
Note that old socket fd1 will be used for further
listening on new clients while new socket fd2 will be
used for currently connected client data transfer. When
we close the connection with current client then fd2 will
perish but fd1 will continue to exist.
Berkeley Sockets ..ACCEPT primitive
The client identity is now known and now clients
address data is filled up in sockets client address
structure.
The server can then fork off to create another process
or thread to handle the new connection for original
socket. Each time, it connects to one new client from
queue, it will spawn a new socket (fd3, fd4 etc.) to
handle it and maintain old socket (fd1) to service next
in queue.
First 4 primitives are for server only. Executing all 4
completes connection phase.
It returns 0 as success and -1 as failure.
Berkeley Sockets ..CONNECT primitive
This primitive causes client to send a request TPDU to
sever, and then to block waiting for a connection
request acknowledgement or confirmation to arrive
from server.
BIND primitive is not needed at client because client
always knows its own address as well as servers
address and that is fully specified in this primitive.
Once the acknowledgement TDPU from server arrives,
client unblocks, and connection is established.
Now client and server can both send or receive the data
to each other.
It returns 0 as success and -1 as failure.
Berkeley Sockets.. SEND RECEIVE & CLOSE primitives
These 3 primitives are common to both server and client.
SEND primitive is implemented as write command while
RECEIVE is invoked as read command.
Both commands use 3 arguments- fd, buffer_label and
number_of_bytes to be transferred.
read and write both return the actual number of bytes transferred
and we need to put them in infinite loop until the whole array is
transferred.
CLOSE is symmetric i.e., it can be started by any one of the two
hosts. Once both sides execute it and exchange packets, the
resources for socket are released.
Data Transfer Primitives
The basic purpose of establishing a connection is to
transfer data. The primitives are available to send or
receive the data in a array whose length can be set by
calling function. So to send just a character, we can
set the length to 1 byte.
The Berkeley primitives are read and write.
However, we can also use send() and recv()
or sendto() and recvfrom() for sending and receiving
data to/from a remote socket.
One should check the version of OS or TCP/IP
library about, which of the above pair is available for
data transfer and what is its precise syntax.
TCP SOCKET FLOW DIAGRAM
Sample code for TCP Client & Server
We will now study how to do socket programming.
On client side the code will use socket(), connect(), read
(),write()and close() functions or primitives
On server side we will use socket() for passive open
followed by
Bind(), then Listen() and finally accept() primitives
After that we will use read/write functions and may or
may not close the socket.
It will be very important to study how the data structure
for storing IP and port no and other parameters are
declared and used.
TCP Client Code - Create a socket
This first thing to do is create a socket. The socket function does this.
#include<stdio.h>
#include<sys/socket.h>
int main(int argc , char *argv[])
{
int fd1;
fd1 = socket(AF_INET , SOCK_STREAM , 0);
if (fd1 == -1) {printf("Could not create socket");}
return 0;
}
TCP Client Code - Create a socket (2)
Function socket() creates a socket and returns a descriptor fd1
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 IPPR
We will now connect to a remote server on a certain port
number. So we need 2 things, server 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.
TCP Client Code - Socket Data Structure
In Berkeley sockets it is defined as sockaddr_in
struct sockaddr_in {
short sin_family; // e.g. AF_INET, AF_INET6
unsigned short sin_port; // e.g. htons (3490)
struct in_addr sin_addr; // see struct in_addr, below
char sin_zero[8]; // zero this if you want to
};
struct in_addr {
unsigned long s_addr; // load with inet_pton()
// the address stored here is a 32-bit IP address derived from
// human readable form like 192.168.1.2
};
Some explanation..(2)
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 32-bit long format. See code below:
Endianness
The terms endian and endianness refer to the convention used to
interpret the bytes making up a data word when those bytes are
stored in computer memory.
Big-endian systems store the most significant byte of a word in
the smallest address and the least significant byte is stored in the
largest address. (IBM)
Little-endian systems, in contrast, store the least significant byte in
the smallest address.(Intel)
Big-endian is the most common convention in data networking
(including IPv4 or IPv6), hence its pseudo-synonym network byte
order, and little-endian is popular (though not universal) among
microprocessors in part due to Intel's significant historical influence
on microprocessor designs.
Conversion from one notation to other
Following functions are used to convert from h (host) to n
(network) or vice versa. S is for short or 16 bit number i.e.
for converting Port No.
L is for long or 32 bit number for converting IP address.
htons() ; // host to network short
htonl(); // host to network long
ntohs();// network to host short
ntohl(); //network to host long
Some explanation..
#include <sys/types.h>
#include <netinet/in.h>
unsigned short htons(unsigned short host_short)
The htons() function is used to convert a short (2-byte)
integer from the local host byte order to standard network
byte order.
host_short(Input) The 2-byte integer in local host byte order
that is to be converted to standard network byte order.
Return Value
htons() returns an integer. Possible values are:
n (where n is the 2-byte integer in standard network byte
order)
TCP Client code to connect to server
// set up servers parameters before connect is executed.
server.sin_addr.s_addr = inet_addr("74.125.235.20");// IP address set
server.sin_family = AF_INET;
server.sin_port = htons( 3490 );//// Port No. set
//Connect to remote server, see pointer typecasting.
if (connect(fd1 , (struct sockaddr *) &server , sizeof(server)) < 0)
{
puts("connect error");
return 1;
}
puts("Connected");
return 0;
}
TCP Client Code - send data over socket
Function send() will simply send data. It needs the socket descriptor fd1,
the data to send and its size. Here is a very simple example of
sending some data to server:
//Send some data
char *message = Hello From Client To Server";
if( send(fd1 , message , strlen(message) , 0) < 0)
{
puts("Send failed");
return 1;
}
puts("Data Sent\n");
TCP Client Code receive data over socket
Function recv () is used to receive data on a socket. In the following
example we expect the echo server to echo back same number of
characters as sent with just incrementing each character by 1:
//Receive a reply from the server
char *server_reply[100];
if( recv(fd1, server_reply , strlen(message) , 0) < 0)
{ puts("recv failed"); }
puts("Reply received\n");
puts(server_reply);// print received character string.
// We can also use read() as follows:
read(fd1, server_reply , strlen(message));
TCP Close socket
Function close is used to close the socket. Need to include the
<unistd.h>
header file for this. That is all for client side.
close(fd1);
TCP Server code - create a socket
This first thing to do is create a socket. The socket function does this.
#include<stdio.h>
#include<sys/socket.h>
int main(int argc , char *argv[])
{
int fd1, fd2, c;// fd2 and c will be used later.
struct sockaddr_in server;
fd1 = socket(AF_INET , SOCK_STREAM , 0);
if (fd1 == -1) {printf("Could not create socket"); }
}
TCP Server code create address structure
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.
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 3490);
// INADDR_ANY means client IP is not important
// for socket connection, any client IP will do.
TCP Server code bind a socket
The bind function usage is here:
//Bind
if( bind(fd1,(struct sockaddr *) &server ,
sizeof(server)) < 0)
{
puts("bind failed");
}
puts("bind done");
TCP Server code Listen on the socket
After binding a socket use function listen to put the
socket in listening mode.
//Listen
listen(fd1 , 3); // create space for 3 clients in queue.
TCP Server code Accept on the socket
// This function accepts request by queued client
// request. Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
fd2 = accept(fd1, (struct sockaddr *)&client,
(socklen_t*)&c);
if (fd2 <0) {
perror("accept failed");
}
puts("Connection accepted");
// Note we will now use fd2 for read write and not fd1.
TCP Server code what is clients IP?
// For fun let us print the IP address and port
// number of connected client. First convert dotted
// representation to 32- bit integer using ntoa.
char *client_ip = inet_ntoa(client.sin_addr);
// convert network byte order to host byte order,
int client_port = ntohs(client.sin_port);
printf("\N %d Client IP address is = ",client_ip);
printf("\N %d Client Port no is = ",client_port);
TCP Server code wait for a char to arrive!
// connection is made, now wait for incoming character,
// increment it and echo it back.
char c_in, c_out;// single char input and output buffer.
while ( (read(fd2, c_in , 1) <1);
{// keep looping till a char is received from client.
}
// we are here means atleast one char has arrived in
// input buffer.
TCP Server code read a char and echo it back
// display received character.
printf("%c", c_in);// display it on screen
c_out = c_in +1;// increment outgoing char.
if( send(fd2, c_out , 1 , 0) < 0)
{
printf("\n Send failed");
return (-10);
}
// we are here means send was successful so print sent char
// on display.
printf("%c",c_out);// display it on screen
TCP Server code Now what?
Server has waited for a char to come,
received it, incremented it and sent it back. It
is now up to us to either close the connection
of just to be in a finite loop ( do it for 10
characters and then stop) or put this in an
infinite loop.
The choice is ours depending upon what we
intend our server to do.
TCP Server code A note on receive
Note that receive function reads all the char waiting in
socket input buffer and returns value of n i.e. number
of bytes read, in a buffer whose address is supplied by
us.
The value of n could be much less than what we are
expecting.
So we need to call receive function again and again as
given here in this code snippet.
TCP Server code Multiple read
char buf[256];// buffer where to store incoming char.
int maxLen = sizeof(buf); // maxLen will be 256 initially.
char *ptr = buffer;// ptr points to beginning of buf
int n = len = 0;// define two temp variables.
// read till buf is full or 256 bytes are read.
while( (n = recv(fd2, ptr,maxLen,0) ) > 0)
{// recv has read n char so increment ptr and decrement no
// of bytes more to be read.
ptr = ptr + n; // increment pointer by n.
maxLen = maxLen-n;// decrement number yet to come.
len = len + n ;// increment no of bytes recd so far
}// the while loop will run till maxLen becomes 0.
Socket
Programming
Example:
Internet File
Server
Client code using
sockets.
6-6-1
Socket
Programming
Example:
Internet File
Server (2)
Server code using
sockets.
Sample code for UDP Client & Server
We will now study how to do UDP socket programming.
On client side the code will use socket(), bind(), sendto()
and recvfrom() functions or primitives.
On server side we will use socket() for passive open
followed by Bind() primitives.
After that we will use sendto() and recvfrom() functions
or primitives and may or may not close the socket.
It will be very important to study how the data structure
for storing IP and port no and other parameters are
declared and used.
Note it is simpler than TCP. See link below:
http://www.binarytides.com/programming-udp-sockets-c-linux/
UDP SOCKET FLOW DIAGRAM
Some interesting differences with TCP
The most important difference is that UDP sockets are not
connection oriented. More technically speaking, a UDP
server does not accept connections and a UDP client does
not connect to server.
The server will bind and then directly receive data and the
client shall directly send the data.
So lets first make a very simple ECHO server with UDP
socket. The flow of the code would be
socket() -> bind() -> recvfrom() -> sendto()
There is only one file descriptor needed in UDP.
After one transaction, socket can be closed.
UDP Server code Include Files
This first thing to do is create a socket. The socket function does this.
#include<stdio.h> //printf
#include<string.h> //memset
#include<stdlib.h> //exit(0);
#include<arpa/inet.h>
#include<sys/socket.h>
#define BUFLEN 512 //Max length of buffer
#define PORT 8888 //The port no on which to listen for
incoming data
UDP Server code - create a socket
int main(void)
{// let us first define some variables.
struct sockaddr_in server, client; // define two socket structures.
int fd, i, recv_len, slen = sizeof(client) ;
char buf[BUFLEN];
//crate a UDP socket, see the DGRAM parameter.
if ( (fd=socket(AF_INET, SOCK_DGRAM,
IPPROTO_UDP)) == -1)
{
die("socket");// this function is for error handling.
}
UDP Server code prepare data
structure for socket and bind
// zero out the structure
memset((char *) &server, 0, sizeof(server));
// set up parameters for server address fields.
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr.s_addr = htonl (INADDR_ANY);
//bind socket to port
if ( bind(fd , (struct sockaddr*)&server, sizeof(server) ) == -1)
{ die("bind"); }
UDP Server code receive first
//keep listening for data in infinite loop
while(1)
{
printf("Waiting for data...");
fflush(stdout);// clears output stream to
display.
//try to receive some data, this is a blocking call
if ((recv_len = recvfrom(fd, buf, BUFLEN, 0,
(struct sockaddr *) &client, &slen)) == -1)
{ die("recvfrom()"); }
// Note buf, BUFLEN, client and &slen.
UDP Server code print it
// print details of the client/peer and the data
// received
printf("Received packet from %s:%d\n",
inet_ntoa(client.sin_addr), ntohs(client.sin_port));
printf("Data: %s\n" , buf);
UDP Server code send next & close
//now reply the client with the same data
if (sendto(fd, buf, recv_len, 0, (struct
sockaddr*) &client, slen) == -1)
{die("sendto()");}
// Note fd, buf, recv_len, client and slen. Close
socket after transaction is done.
close(fd);
return 0;
UDP Client code
#include<stdio.h> //printf
#include<string.h> //memset
#include<stdlib.h> //exit(0);
#include<arpa/inet.h>
#include<sys/socket.h>
#define SERVER "127.0.0.1 // Local Loopback
#define BUFLEN 512 //Max length of buffer
#define PORT 8888 //The port on which to send data
UDP Client code
#include<stdio.h> //printf
#include<string.h> //memset
#include<stdlib.h> //exit(0);
#include<arpa/inet.h>
#include<sys/socket.h>
#define SERVER "127.0.0.1 // Local Loopback
#define BUFLEN 512 //Max length of buffer
#define PORT 8888 //The port on which to send data
void die(char *s)
{ perror(s); exit(1); }
UDP Client code Create socket
struct sockaddr_in server;
int fd, i, slen=sizeof(server);
char buf[BUFLEN];
char message[BUFLEN];
if ( (fd=socket(AF_INET, SOCK_DGRAM,
IPPROTO_UDP)) == -1)
{
die("socket");
}
UDP Client code socket structure
// fill zeroes and set parameters for bind.
memset((char *) &server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
// SERVER loopback number is stored in server.sin_addr
if (inet_aton(SERVER , &server.sin_addr) == 0)
{
fprintf(stderr, "inet_aton() failed\n");
exit(1);
}
// client is ready to transact data with server.
UDP Client code Send message
while(1) // we can put read write in infinite loop.
{ printf("Enter message : ");
gets(message);// get message from keyboard.
//send the message to server in same PC.
if (sendto(fd, message, strlen(message) , 0 ,
(struct sockaddr *) &server, slen)==-1)
{
die("sendto()");
}
UDP Client code Receive message
//receive a reply and print it. clear the buffer by filling
// null, it might have previously received data.
memset(buf,'\0', BUFLEN);
//try to receive some data, this is a blocking call
if (recvfrom(fd, buf, BUFLEN, 0, (struct
sockaddr *) &server, &slen) == -1)
{die("recvfrom()");}
puts(buf);// print data echoed from server.
} // end of infinite loop
close(fd);
return 0;