Network Interface Guide

Datagram Sockets

A datagram socket provides a symmetric data exchange interface. There is no requirement for connection establishment. Each message carries the destination address. Figure 2-2 shows the flow of communication between server and client.


Note -

The bind(3SOCKET) step shown below for the server is optional.


Figure 2-2 Connectionless Communication Using Datagram Sockets

Graphic

Datagram sockets are created as described in "Socket Creation". If a particular local address is needed, the bind(3SOCKET) operation must precede the first data transmission. Otherwise, the system sets the local address and/or port when data is first sent. To send data, sendto(3SOCKET) is used:

sendto(s, buf, buflen, flags, (struct sockaddr *) &to, tolen);

The s, buf, buflen, and flags parameters are the same as in connection-oriented sockets. The to and tolen values indicate the address of the intended recipient of the message. A locally detected error condition (such as an unreachable network) causes a return of -1 and errno to be set to the error number.

To receive messages on a datagram socket, recvfrom(3SOCKET) is used:

recvfrom(s, buf, buflen, flags, (struct sockaddr *) &from, &fromlen);

Before the call, fromlen is set to the size of the from buffer. On return, it is set to the size of the address from which the datagram was received.

Datagram sockets can also use the connect(3SOCKET) call to associate a socket with a specific destination address. It can then use the send(3SOCKET) call. Any data sent on the socket without explicitly specifying a destination address is addressed to the connected peer, and only data received from that peer is delivered. Only one connected address is permitted for one socket at a time. A second connect(3SOCKET) call changes the destination address. Connect requests on datagram sockets return immediately. The system records the peer's address. accept(3SOCKET), and listen(3SOCKET) are not used with datagram sockets.

While a datagram socket is connected, errors from previous send(3SOCKET) calls can be returned asynchronously. These errors can be reported on subsequent operations on the socket, or an option of getsockopt(3SOCKET), SO_ERROR, can be used to interrogate the error status.

Example 2-3 shows how to send an Internet call by creating a socket, binding a name to the socket, and sending the message to the socket.


Example 2-3 Sending an Internet Family Datagram

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
 
#define DATA "The sea is calm, the tide is full . . ."
 
/*
 * Here I send a datagram to a receiver whose name I get from
 * the command line arguments. The form of the command line is:
 * dgramsend hostname portnumber
 */
main(argc, argv)
   int argc, errnum;
   char *argv[];
{
   int sock;
   struct sockaddr_in6 name;
   struct hostent *hp;
 
   /* Create socket on which to send. */
   sock = socket(AF_INET6,SOCK_DGRAM, 0);
   if (sock == -1) {
      perror("opening datagram socket");
      exit(1);
   }
   /*
    * Construct name, with no wildcards, of the socket to ``send''
    * to. getinodebyname returns a structure including the network
    * address of the specified host. The port number is taken from
    * the command line.
    */
   hp = getipnodebyname(AF_INET6, argv[1], AI_DEFAULT, &errnum);
   if (hp == (struct hostent *) 0) {
      fprintf(stderr, "%s: unknown host\n", argv[1]);
      exit(2);
   }
   bzero (&sin6, sizeof (sin6));
   bzero (&name, sizeof (name));
   memcpy((char *) &name.sin6_addr, (char *) hp->h_addr,
      hp->h_length);
   name.sin6_family = AF_INET6;
   name.sin6_port = htons(atoi(argv[2]));
   /* Send message. */
   if (sendto(sock,DATA, sizeof DATA ,0,
      (struct sockaddr *) &name,sizeof name) == -1)
      perror("sending datagram message");
   close(sock);
   exit(0);
}

Example 2-4 shows how to read an Internet call by creating a socket, binding a name to the socket, and then reading from the socket.


Example 2-4 Reading Internet Family Datagrams

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
 
/*
 * This program creates a datagram socket, binds a name to it, then
 * reads from the socket.
 */
 
main()
{
   int sock, length;
   struct sockaddr_in6 name;
   char buf[1024];
 
   /* Create socket from which to read. */
   sock = socket(AF_INET6, SOCK_DGRAM, 0);
   if (sock == -1) {
      perror("opening datagram socket");
      exit(1);
   }
   /* Create name with wildcards. */
   bzero (&sin6, sizeof (sin6));
   name.sin6_family = AF_INET6;
   name.sin6_addr.s6_addr = in6addr_any;
   name.sin6_port = 0;
   if (bind(sock,(struct sockaddr *)&name, sizeof name) == -1) {
      perror("binding datagram socket");
      exit(1);
   }
   /* Find assigned port value and print it out. */
   length = sizeof(name);
   if (getsockname(sock,(struct sockaddr *) &name, &length)
         == -1) 	{
      perror("getting socket name");
      exit(1);
   }
   printf("Socket port #%d\n", ntohs(name.sin6_port));
   /* Read from the socket. */
   if (read(sock, buf, 1024) == -1 )
      perror("receiving datagram packet");
   /* Assumes the data is printable */
   printf("-->%s\n", buf);
   close(sock);
   exit(0);
}