You are on page 1of 9

Elementary UDP Sockets

Srinu Bevara Page 1



UNIT-V
Elementary UDP Sockets
INTRODUCTION
There are some fundamental differences between applications written using TCP versus those that use UDP.
These are because of the differences in the two transport layers: UDP is a connectionless, unreliable,
datagram protocol, quite unlike the connection-oriented, reliable byte stream provided by TCP.
Nevertheless, there are instances when it makes sense to use UDP instead of TCP. Some popular
applications are built using UDP: DNS, NFS, and SNMP, for example.
The below figure shows the function calls for a typical UDP client/server. The client does not establish a
connection with the server. Instead, the client just sends a datagram to the server using the sendto function,
which requires the address of the destination (the server) as a parameter. Similarly, the server does not
accept a connection from a client. Instead, the server just calls the recvfromfunction, which waits until data
arrives from some client. recvfrom returns the protocol address of the client, along with the datagram, so the
server can send a response to the correct client.
The figure also shows a timeline of the typical scenario that takes place for a UDPclient/server exchange.
We can compare this to the typical TCP exchange. We will also describe the new functions that we us with
UDP sockets, recvfrom and sendto, and redo our echo client/server to use UDP. We will also describe the
use of the connect function with a UDP socket, and the concept of asynchronous errors.

Figure 1 : Socket functions for UDP client/server
Elementary UDP Sockets

Srinu Bevara Page 2

send(), sendto()
Send data out over a socket
Prototypes
#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int s, const void *buf, size_tlen, int flags);
ssize_tsendto(int s, const void *buf, size_tlen, int flags, conststructsockaddr *to, socklen_ttolen);

Description
These functions send data to a socket. Generally speaking, send() is used for TCP SOCK_STREAM connected sockets,
and sendto() is used for UDP SOCK_DGRAM unconnected datagram sockets. With the unconnected sockets, you
must specify the destination of a packet each time you send one, and that's why the last parameters of sendto()
define where the packet is going.
With both send() and sendto(), the parameter s is the socket, buf is a pointer to the data you want to send, len is the
number of bytes you want to send, and flags allows you to specify more information about how the data is to be
sent. Set flags to zero if you want it to be "normal" data. Here are some of the commonly used flags, but check your
local send() man pages for more details:
MSG_OOB Send as "out of band" data. TCP supports this, and it's a way to tell the receiving
system that this data has a higher priority than the normal data. The receiver will
receive the signal SIGURG and it can then receive this data without first receiving
all the rest of the normal data in the queue.
MSG_DONTROUTE Don't send this data over a router, just keep it local.
MSG_DONTWAIT If send() would block because outbound traffic is clogged, have it return EAGAIN.
This is like a "enable non-blocking just for this send." See the section on blocking
for more details.
MSG_NOSIGNAL If you send() to a remote host which is no longer recv()ing,you'll typically get the
signal SIGPIPE. Adding this flag prevents that signal from being raised.

Return Value
Returns the number of bytes actually sent, or -1 on error (and errno will be set accordingly.) Note that the number of
bytes actually sent might be less than the number you asked it to send! See the section on handling partial send()s
for a helper function to get around this.
Also, if the socket has been closed by either side, the process calling send() will get the signal SIGPIPE. (Unless send()
was called with the MSG_NOSIGNAL flag.)


Elementary UDP Sockets

Srinu Bevara Page 3

recv(), recvfrom()
Receive data on a socket
Prototypes
#include <sys/types.h>
#include <sys/socket.h>
ssize_trecv(int s, void *buf, size_tlen, int flags);
ssize_trecvfrom(int s, void *buf, size_tlen, int flags, structsockaddr *from, socklen_t *fromlen);

Description
Once you have a socket up and connected, you can read incoming data from the remote side using the recv() (for
TCP SOCK_STREAM sockets) and recvfrom() (for UDP SOCK_DGRAMsockets).
Both functions take the socket descriptor s, a pointer to the buffer buf, the size (in bytes) of the buffer len, and a set
of flags that control how the functions work.
Additionally, the recvfrom() takes a structsockaddr*, from that will tell you where the data came from, and will fill in
fromlen with the size of structsockaddr. (You must also initializefromlen to be the size of from or structsockaddr.)
So what wondrous flags can you pass into this function? Here are some of them, but you should check your local
man pages for more information and what is actually supported on your system. You bitwise-or these together, or
just set flags to 0 if you want it to be a regular vanilla recv().
MSG_OOB Receive Out of Band data. This is how to get data that has been sent to you with the
MSG_OOB flag in send(). As the receiving side, you will have had signal SIGURG raised
telling you there is urgent data. In your handler for that signal, you could call
recv()with this MSG_OOB flag.
MSG_PEEK If you want to call recv() "just for pretend", you can call it with this flag. This will tell
you what's waiting in the buffer for when you call recv() "for real" (i.e. without the
MSG_PEEK flag. It's like a sneak preview into the next recv() call.
MSG_WAITALL Tell recv() to not return until all the data you specified in the len parameter. It will
ignore your wishes in extreme circumstances, however, like if a signal interrupts the
call or if some error occurs or if the remote side closes the connection, etc. Don't be
mad with it.

When you call recv(), it will block until there is some data to read. If you want to not block, set the socket to non-
blocking or check with select() or poll() to see if there is incoming data before calling recv() or recvfrom().
Return Value
Returns the number of bytes actually received (which might be less than you requested in the len parameter), or -1
on error (and errno will be set accordingly.)
Elementary UDP Sockets

Srinu Bevara Page 4

If the remote side has closed the connection, recv() will return 0. This is the normal method for determining if the
remote side has closed the connection. Normality is good, rebel!
UDP Echo Server
main Function

Figure 2 : Simple echo client/server using UDP
1 #include "unp.h"
2 int
3 main(intargc, char **argv)
4 {
5 intsockfd;
6 structsockaddr_inservaddr, cliaddr;
7 sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
8 bzero(&servaddr, sizeof(servaddr));
9 servaddr.sin_family = AF_INET;
10 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
11 servaddr.sin_port = htons(SERV_PORT);
12 Bind(sockfd, (SA *) &servaddr, sizeof(servaddr));
13 dg_echo(sockfd, (SA *) &cliaddr, sizeof(cliaddr));
14 }
712We create a UDP socket by specifying the second argument to socket as SOCK_DGRAM (a datagram
socket in the IPv4 protocol). As with the TCP server example, the IPv4 address for the bind is specified as
INADDR_ANY and the server's well-known port is the constant SERV_PORT from the unp.h header.
13 The function dg_echo is called to perform server processing.
dg_echo Function
1 #include "unp.h"
2 void
3 dg_echo(intsockfd, SA *pcliaddr, socklen_tclilen)
4 {
5 int n;
6 socklen_tlen;
7 char mesg[MAXLINE];
8 for ( ; ; ) {
9 len = clilen;
10 n = Recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);
11 Sendto(sockfd, mesg, n, 0, pcliaddr, len);
12 }
13 }

812This function is a simple loop that reads the next datagram arriving at the server's port using recvfrom and
sends it back using sendto.
Read datagram, echo back to sender
Elementary UDP Sockets

Srinu Bevara Page 5

dg_echo function is a simple loop that reads the next datagram arriving at the servers port using recvfrom
and sends it back using sendto.
Despite the simplicity of this function, there are numerous details to consider,
o This function never terminates,
Since udp is a connectionless protocol, there is nothing like an EOF as TCp.
o This function provides an iterative server
There is no call to fork, so a single server process handles any and all clients.
o Most TCP server are concurrent
o Most UDP server are iterative

Figure 3 : TCP client/server with two clients
There are two connected sockets and each of the two connected sockets on the server host has its own socket
receive buffer.

Figure 4 : UDP client/server with two clients
There is only one server process and it has a single socket on which it receives all arriving datagrams and sends all
responses. That socket has a receive buffer into which all arriving datagrams are placed
UDP Echo Client
main Function
1 #include "unp.h"
2 int
3 main(intargc, char **argv)
4 {
5 intsockfd;
6 structsockaddr_inservaddr;
7 if(argc != 2)
8 err_quit("usage: udpcli<IPaddress>");
9 bzero(&servaddr, sizeof(servaddr));
10 servaddr.sin_family = AF_INET;
11 servaddr.sin_port = htons(SERV_PORT);
Elementary UDP Sockets

Srinu Bevara Page 6

12 Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
13 sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
14 dg_cli(stdin, sockfd, (SA *) &servaddr, sizeof(servaddr));
15 exit(0);
16 }
912 An IPv4 socket address structure is filled in with the IP address and port number of the server. This
structure will be passed to dg_cli, specifying where to send datagrams.
1314 A UDP socket is created and the function dg_cli is called.
dg_cli Function
1 #include "unp.h"
2 void
3 dg_cli(FILE *fp, intsockfd, const SA *pservaddr, socklen_tservlen)
4 {
5 int n;
6 char sendline[MAXLINE], recvline[MAXLINE + 1];
7 while (Fgets(sendline, MAXLINE, fp) != NULL) {
8 Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);
9 n = Recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);
10 recvline[n] = 0; /* null terminate */
11 Fputs(recvline, stdout);
12 }
13 }
712 There are four steps in the client processing loop: read a line from standard input using fgets, send the
line to the server using sendto, read back the server's echo using recvfrom, and print the echoed line to
standard output using fputs.
There are four steps in the client processing loop
Read a line from standard input using fgets
Send the line to server using sendto
Read back the servers echo using recvfrom
Print the echoed line to standard output using fputs.
Notice that the call to recvfrom specifies a null pointer as the ffifth and sixth arguments, this tells the
kernel that we are not interested in knowing who send the reply
Lost Datagrams
Our UDP client/server example is not reliable. If a client datagram is lost (say it is discarded by some router between
the client and server), the client will block forever in its call to recvfrom in the function dg_cli, waiting for a server
reply that will never arrive. Similarly, if the client datagram arrives at the server but the server's reply is lost, the
client will again block forever in its call to recvfrom. A typical way to prevent this is to place a timeout on the client's
call to recvfrom.
Just placing a timeout on the recvfrom is not the entire solution. For example, if we do time out, we cannot tell
whether our datagram never made it to the server, or if the server's reply never made it back. If the client's request
was something like "transfer a certain amount of money from account A to account B" (instead of our simple echo
server), it would make a big difference as to whether the request was lost or the reply was lost.
Elementary UDP Sockets

Srinu Bevara Page 7


connect Function with UDP
an asynchronous error is not returned on a UDP socket unless the socket has been connected. Indeed, we are able to
call connect for a UDP socket. But this does not result in anything like a TCP connection: There is no three-way
handshake. Instead, the kernel just checks for any immediate errors (e.g., an obviously unreachable destination),
records the IP address and port number of the peer (from the socket address structure passed to connect), and
returns immediately to the calling process.
Overloading the connect function with this capability for UDP sockets is confusing. If theconventionthat sockname
is the local protocol address and peername is the foreign protocol address is used, then a better name would have
been setpeername. Similarly, a better name for the bind function would be setsockname. With this capability, we
must now distinguish between
An unconnected UDP socket, the default when we create a UDP socket
A connected UDP socket, the result of calling connect on a UDP socket
With a connected UDP socket, three things change, compared to the default unconnected UDP socket:
1. We can no longer specify the destination IP address and port for an output operation. That is, we do not use
sendto, but write or send instead. Anything written to a connected UDP socket is automatically sent to the
protocol address (e.g., IP address and port) specified by connect.
2. We do not need to use recvfrom to learn the sender of a datagram, but read, recv, or recvmsg instead. The
only datagrams returned by the kernel for an input operation on a connected UDP socket are those arriving
from the protocol address specified in connect. Datagrams destined to the connected UDP socket's local
protocol address (e.g., IP address and port) but arriving from a protocol address other than the one to which
the socket was connected are not passed to the connected socket. This limits a connected UDP socket to
exchanging datagrams with one and only one peer.
3. Asynchronous errors are returned to the process for connected UDP sockets. The corollary, as we previously
described, is that unconnected UDP sockets do not receive asynchronous errors.
Elementary UDP Sockets

Srinu Bevara Page 8


Lack of Flow Control with UDP
We observe two cases:
CASE 1: SLOW CLIENT FAST SERVER
CASE 2: FAST CLIENT SLOW SERVER
WE KNOW THE STATEMENT AT ANY MOMENT OF TIME, SENDER WILL NOT OVERFLOW THE RECEIVER BUFFER
FROM TCP CONCEPT.
Based on this statement, we explain the concept like this:
W.r.to Client:
SLOW-BIT RATE IS LESS
FAST-BIT RATE IS MORE
W.r.to Server:
SLOW-RECEIVER BUFFER (WINDOW) SIZE IS LESS
FAST- RECEIVER BUFFER (WINDOW) SIZE IS MORE
In CASE 2, the Datagrams are lost to the maximum extent. This is the normal situation that is present in UDP
Communication.
In CASE 1, the Datagrams are maintained and delivered to the receiver (as there will be flow control).
Consider the following example for CASE 2:
The client sent 2,000 datagrams, but the server application received only 30 of these, for a 98% loss rate. is no
indication whatsoever to the server application or to the client application that these datagrams were As we
have said, UDP has no flow control and it is unreliable. It is trivial, as we have shown, for a UDP sender overrun
the receiver.
If we look at the netstat output, the total number of datagrams received by the server host (not the server
application) is 2,000 (73,208 - 71,208). The counter "dropped due to full socket buffers" indicates how many
Elementary UDP Sockets

Srinu Bevara Page 9

datagrams were received by UDP but were discarded because the receiving socket's receive queue was full 775
of TCPv2). This value is 1,970 (3,491 - 1,971), which when added to the counter output by the application.
The following Output specifies this:

THE FIRST SET OF LINES IS WHEN THE DATAGRAMS ARE NOT YET OBTAINED AT THE CLIENT SIDE (BEFORE THIS
COMMUNICATION).
THE SECOND SET OF LINES IS WHEN DATAGRAMS ARE COMMUNICATED IN THIS (CURRENT) COMMUNICATION.
This specifies clearly that there is lack of flow control with the UDP Service.
Determining Outgoing Interface with UDP
A connected UDP socket can also be used to determine the outgoing interface that will be used to a particular
destination. This is because of a side effect of the connect function when applied to a UDP socket: The kernel
chooses the local IP address (assuming the process has not already called bind to explicitly assign this). This local IP
address is chosen by searching the routing table for the destination IP address, and then using the primary IP address
for the resulting interface.

In the above figure, UDP Client connects with the UDP Server using bind(). But, in order for the datagrams to move
from UDP Client to UDP Server, they should move through intermediate routers. So, PEER System now becomes R1
but not UDP Server. This is because we are using connect() within the UDP communication.

You might also like