Programming Interfaces Guide

Datagram Sockets

A datagram socket provides a symmetric data exchange interface without requiring connection establishment. Each message carries the destination address. The following figure shows the flow of communication between server and client.

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

Figure 7–2 Connectionless Communication Using Datagram Sockets

This graphic depicts data flow between a server and client, using the sendto and recvfrom functions.

Create datagram sockets 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 or port when data is first sent. Use sendto(3SOCKET) to send data.

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.

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

To receive messages on a datagram socket, recvfrom(3SOCKET) is used. Before the call, fromlen is set to the size of the from buffer. On return, fromlen 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. The socket can then use the send(3SOCKET) call. Any data that is sent on the socket that does not explicitly specify a destination address is addressed to the connected peer. Only the data that is received from that peer is delivered. A socket can have only one connected address 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. Neither accept(3SOCKET) nor listen(3SOCKET) are used with datagram sockets.

A datagram socket can return errors from previous send(3SOCKET) calls asynchronously while the socket is connected. The socket can report these errors on subsequent socket operations. Alternately, the socket can use an option of getsockopt(3SOCKET), SO_ERROR to interrogate the error status.

The following example code 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 7–4 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;
    char *argv[];
{
    int sock, errnum;
    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(argv[1], AF_INET6, AI_DEFAULT, &errnum);
    if (hp == (struct hostent *) 0) {
        fprintf(stderr, "%s: unknown host\n", argv[1]);
        exit(2);
    }
    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);
}

The following sample code shows how to read an Internet call by creating a socket, binding a name to the socket, and then reading from the socket.


Example 7–5 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 (&name, sizeof (name));
   name.sin6_family = AF_INET6;
   name.sin6_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);
}