Data Framing (TCP vs. UDP)

 < Day Day Up > 



Although the topic of data framing is not really an advanced Sockets API topic, it is a behavior that is commonly misunderstood. Framing defines the basic units of information that are transported between two socket endpoints. In the case of TCP, information is transported as a stream, and, therefore, no framing exists. For UDP, information is transported as datagrams, which means that data is framed. UDP provides a message-oriented protocol in which the unit of information sent by the sender is what is received by the receiver. Even if more data was sent after the first segment of information, the receiver still receives the unit sent by the write call. TCP, being stream-based, operates in a very different manner. If the sender writes three blocks of information, the receiver may receive all three blocks in a single read. This is because TCP is stream-oriented and has no concept of framing.

Let’s look at some examples that illustrate what’s happening here. In Listing 6.10, we analyze TCP from the perspective of framing.

Listing 6.10 Source illustrating framing (lack of) in TCP stream sockets (tcpframe.c).

start example
#include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <fcntl.h> #define MAX_BUF         100 main() {   int s1, s2, s3;   struct sockaddr_in saddr;   int ret, on=1;   char outbuf[10];   char inbuf[MAX_BUF+1];   /* Create two stream sockets */   s1 = socket( AF_INET, SOCK_STREAM, 0 );   s2 = socket( AF_INET, SOCK_STREAM, 0 );   /* Make s1 (the server) reusable from an    * address perspective.    */   ret = setsockopt( s1, SOL_SOCKET, SO_REUSEADDR,                      &on, sizeof(on) );   /* Create the address for the server socket */   saddr.sin_family = AF_INET;   saddr.sin_port = htons( 8192 );   saddr.sin_addr.s_addr = htonl( INADDR_ANY );   /* Bind the address to s1 */   ret = bind( s1, (struct sockaddr_in *)&saddr, sizeof(saddr) );   /* Specify willingness to accept connections */   ret = listen( s1, 1 );   /* Make the client socket nonblocking */   fcntl( s2, F_SETFL, O_NONBLOCK );   /* Connect the two sockets together */   ret = connect( s2, (struct sockaddr_in *)&saddr,                   sizeof(saddr) );   /* Allow the server to accept a new client socket */   s3 = accept( s1, (struct sockaddr_in *)NULL, NULL );   /* Generate some output data */   outbuf[0] = 'a';   outbuf[1] = 0;   /* Make three distinct calls with the data */   ret = write( s3, outbuf, 1 );   ret = write( s3, outbuf, 1 );   ret = write( s3, outbuf, 1 );   /* Sleep for one second */   sleep( 1 );   /* Read the data from the client */   ret = read( s2, inbuf, MAX_BUF );   /* Should have read 3 bytes */   printf( "read %d bytes\n", ret );   /* Close the sockets */   close(s1);   close(s2);   close(s3); }
end example

From Listing 6.10, we see a single application that provides both a TCP server and client that demonstrates passing data. The server and client setup are performed, and then the client is made nonblocking (so that both can coexist within the same application). The interesting aspect of this application begins near the end, where three writes are made of a single byte of data. We sleep for a second to allow the stack to properly migrate the data and then perform a read operation. The numbers of bytes that are read are three, which is the three writes that were performed. From this experiment, we see that no framing occurred because TCP streamed the data without regard to the granularity of the writes.

Let’s now look at the UDP case. UDP differs from TCP in a number of ways, but an important distinction is the inclusion of framing. When a write is performed in UDP, the block of data is a datagram and the framing of the data is preserved for read. Listing 6.11 shows the UDP source that mirrors our TCP source from Listing 6.10.

Listing 6.11 Source illustrating framing in UDP datagram sockets (udpframe.c).

start example
#include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #define MAX_BUF         100 main() {   int s1, s2;   struct sockaddr_in saddr;   int ret, on=1;   char outbuf[10];   char inbuf[MAX_BUF+1];   /* Create two stream sockets */   s1 = socket( AF_INET, SOCK_DGRAM, 0 );   s2 = socket( AF_INET, SOCK_DGRAM, 0 );   /* Make s1 (the server) reusable from an    * address perspective.    */   ret = setsockopt( s1, SOL_SOCKET, SO_REUSEADDR,                      &on, sizeof(on) );   /* Create the address for the server socket */   saddr.sin_family = AF_INET;   saddr.sin_port = htons( 8192 );   saddr.sin_addr.s_addr = htonl( INADDR_ANY );   /* Bind the address to s1 */   ret = bind( s1,                (struct sockaddr_in *)&saddr, sizeof(saddr) );   /* Connect the two sockets together (connected    * datagram socket).    */   ret = connect( s2, (struct sockaddr_in *)&saddr,                   sizeof(saddr) );   /* Generate some output data */   outbuf[0] = 'a';   outbuf[1] = 0;   /* Make three distinct calls with the data */   ret = write( s2, outbuf, 1 );   ret = write( s2, outbuf, 1 );   ret = write( s2, outbuf, 1 );   /* Sleep for one second */   sleep( 1 );   /* Read the data from the client */   ret = read( s1, inbuf, MAX_BUF );   /* Should have read 1 byte */   printf( "read %d bytes\n", ret );   /* Close the sockets */   close(s1);   close(s2); }
end example

What is notable about Listing 6.11 is that instead of reading the accumulated three bytes that were written, only one byte is read. This is because each write specifies the framing of the data, which is preserved at the peer. To read the data, three reads must be performed.

This is a very important distinction and is an important feature of UDP. TCP applications can simulate this behavior by including a layer above the socket to preserve the framing (in a data-dependent fashion), but at the cost of additional processing of the data. This makes UDP a very attractive protocol for message-based communication.



 < Day Day Up > 



BSD Sockets Programming from a Multi-Language Perspective
Network Programming for Microsoft Windows , Second Edition (Microsoft Programming Series)
ISBN: 1584502681
EAN: 2147483647
Year: 2003
Pages: 225
Authors: Jim Ohlund

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net