Programming with sockets

Connectionless sockets

Up to this point we have been concerned primarily with connection-oriented sockets. However, connectionless interactions typical of the datagram facilities found in contemporary packet switched networks are also supported. A datagram socket provides a symmetric interface to data exchange. While processes are still likely to be client and server processes, there is no requirement for connection establishment. Instead, each message includes the destination address.

Datagram sockets are created as described in ``Socket creation''. If a particular local address is needed, the bind operation must precede the first data transmission. Otherwise, the system will set the local address and/or port when data is first sent. To send data, the sendto call is used:

   sendto(s, buf, buflen, flags, (struct sockaddr *)
      &to, tolen);
The s, buf, buflen, and flags parameters are used the same as with connection-oriented sockets. The to and tolen values are used to show the address of the intended recipient of the message. When using an unreliable datagram interface, it is unlikely that any errors will be reported to the sender. When information is present locally that allows the system to recognize a message that can not be delivered (for instance when a network is unreachable), the call will return -1 and the global value errno will contain the error number.

To receive messages on an unconnected datagram socket, the recvfrom call is used:

   recvfrom(s, buf, buflen, flags, (struct sockaddr *)
      &from, &fromlen);
The fromlen parameter initially contains the size of the from buffer; it is modified on return to show the size of the address from which the datagram was received.

In addition to the two calls mentioned above, datagram sockets may also use the connect call to associate a socket with a specific destination address. Here, any data sent on the socket without explicitly specifying the destination address will automatically be addressed to the connected peer, and only data received from that peer will be delivered to the user. Only one connected address is permitted for each socket at one time. A second connect will change the destination address, and a connect to a null address (domain AF_UNSPEC) will disconnect. Connect requests on datagram sockets return immediately; the system simply records the peer's address. By contrast, a connection request on a stream socket initiates establishment of an end-to-end connection. accept and listen are not used with datagram sockets.

While a datagram socket is connected, errors from recent send calls may be returned asynchronously. These errors may be reported on subsequent operations on the socket, or a special socket option used with getsockopt, SO_ERROR, may be used to interrogate the error status.

   #include <sys/types.h>
   #include <sys/socket.h>
   #include <netinet/in.h>
   #include <stdio.h>

/* * The include file <netinet/in.h> defines sockaddr_in as follows: * struct sockaddr_in { * u_char sin_len; * u_char sin_family; * ushort_t sin_port; * struct in_addr sin_addr; * char sin_zero[8]; * }; * * This program creates a datagram socket, binds a name to it, then reads * from the socket. */ main() { int sock, length; struct sockaddr_in name; char buf[1024];

/* Create socket from which to read. */ sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { perror("opening datagram socket"); exit(1); } /* Create name with wildcards. */ name.sin_len = sizeof(name); name.sin_family = AF_INET; name.sin_addr.s_addr = INADDR_ANY; name.sin_port = 0; if (bind(sock, (struct sockaddr *)&name, sizeof(name)) < 0) { perror("binding datagram socket"); exit(1); } /* Find assigned port value and print it out. */ length = sizeof(name); if (getsockname(sock, (struct sockaddr *)&name, &length) < 0) { perror("getting socket name"); exit(1); } printf("Socket port #%d\n", ntohs(name.sin_port)); /* Read from the socket. */ if (read(sock, buf, 1024) < 0) perror("receiving datagram packet"); printf("-->%s\n", buf); close(sock); exit(0); }

   #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; struct sockaddr_in name; struct hostent *hp, *gethostbyname();

/* Create socket on which to send. */ sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { perror("opening datagram socket"); exit(1); } /* * Construct name, with no wildcards, of the socket to send to. * gethostbyname returns a structure including the network address * of the specified host. The port number is taken from the command * line. */ hp = gethostbyname(argv[1]); if (hp == 0) { fprintf(stderr, "%s: unknown host\n", argv[1]); exit(2); } memcpy( (char *)&name.sin_addr, (char *)hp->h_addr, hp->h_length); name.sin_len = sizeof(name); name.sin_family = AF_INET; name.sin_port = htons(atoi(argv[2])); /* Send message. */ if (sendto(sock, DATA, sizeof(DATA), 0, (struct sockaddr *)&name, sizeof(name)) < 0) perror("sending datagram message"); close(sock); exit(0); }

© 2005 The SCO Group, Inc. All rights reserved.
SCO OpenServer Release 6.0.0 -- 02 June 2005