This section describes how to use communication styles that don't use connections (styles SOCK_DGRAM and SOCK_RDM). Using these styles, you group data into packets and each packet is an independent communication. You specify the destination for each packet individually.
Datagram packets are like letters: you send each one independently with its own destination address, and they may arrive in the wrong order or not at all.
The listen and accept functions are not allowed for sockets using connectionless communication styles.
The normal way of sending data on a datagram socket is by using the sendto function, declared in sys/socket.h.
You can call connect on a datagram socket, but this only specifies a default destination for further data transmission on the socket. When a socket has a default destination you can use send (the section called “Sending Data”) or even write (the section called “Input and Output Primitives”) to send a packet there. You can cancel the default destination by calling connect using an address format of AF_UNSPEC in the addr argument. the section called “Making a Connection”, for more information about the connect function.
int function>sendto/function> (int socket, void *buffer. size_t size, int flags, struct sockaddr *addr, socklen_t length) The sendto function transmits the data in the buffer through the socket socket to the destination address specified by the addr and length arguments. The size argument specifies the number of bytes to be transmitted.
The flags are interpreted the same way as for send; see the section called “Socket Data Options”.
The return value and error conditions are also the same as for send, but you cannot rely on the system to detect errors and report them; the most common error is that the packet is lost or there is no-one at the specified address to receive it, and the operating system on your machine usually does not know this.
It is also possible for one call to sendto to report an error owing to a problem related to a previous call.
This function is defined as a cancellation point in multi-threaded programs, so one has to be prepared for this and make sure that allocated resources (like memory, files descriptors, semaphores or whatever) are freed even if the thread is canceled.
The recvfrom function reads a packet from a datagram socket and also tells you where it was sent from. This function is declared in sys/socket.h.
int function>recvfrom/function> (int socket, void *buffer, size_t size, int flags, struct sockaddr *addr, socklen_t *length-ptr) The recvfrom function reads one packet from the socket socket into the buffer buffer. The size argument specifies the maximum number of bytes to be read.
If the packet is longer than size bytes, then you get the first size bytes of the packet and the rest of the packet is lost. There's no way to read the rest of the packet. Thus, when you use a packet protocol, you must always know how long a packet to expect.
The addr and length-ptr arguments are used to return the address where the packet came from. the section called “Socket Addresses”. For a socket in the local domain the address information won't be meaningful, since you can't read the address of such a socket (the section called “The Local Namespace”). You can specify a null pointer as the addr argument if you are not interested in this information.
The flags are interpreted the same way as for recv (the section called “Socket Data Options”). The return value and error conditions are also the same as for recv.
This function is defined as a cancellation point in multi-threaded programs, so one has to be prepared for this and make sure that allocated resources (like memory, files descriptors, semaphores or whatever) are freed even if the thread is canceled.
You can use plain recv (the section called “Receiving Data”) instead of recvfrom if you don't need to find out who sent the packet (either because you know where it should come from or because you treat all possible senders alike). Even read can be used if you don't want to specify flags (the section called “Input and Output Primitives”).
Here is a set of example programs that send messages over a datagram stream in the local namespace. Both the client and server programs use the make_named_socket function that was presented in the section called “Example of Local-Namespace Sockets”, to create and name their sockets.
First, here is the server program. It sits in a loop waiting for messages to arrive, bouncing each message back to the sender. Obviously this isn't a particularly useful program, but it does show the general ideas involved.
#include stdio.h #include errno.h #include stdlib.h #include sys/socket.h #include sys/un.h #define SERVER "/tmp/serversocket" #define MAXMSG 512 int main (void) { int sock; char message[MAXMSG]; struct sockaddr_un name; size_t size; int nbytes; /* Remove the filename first, it's ok if the call fails */ unlink (SERVER); /* Make the socket, then loop endlessly. */ sock = make_named_socket (SERVER); while (1) { /* Wait for a datagram. */ size = sizeof (name); nbytes = recvfrom (sock, message, MAXMSG, 0, (struct sockaddr *) name, size); if (nbytes 0) { perror ("recfrom (server)"); exit (EXIT_FAILURE); } /* Give a diagnostic message. */ fprintf (stderr, "Server: got message: %s\n", message); /* Bounce the message back to the sender. */ nbytes = sendto (sock, message, nbytes, 0, (struct sockaddr *) name, size); if (nbytes 0) { perror ("sendto (server)"); exit (EXIT_FAILURE); } } }
Here is the client program corresponding to the server above.
It sends a datagram to the server and then waits for a reply. Notice that the socket for the client (as well as for the server) in this example has to be given a name. This is so that the server can direct a message back to the client. Since the socket has no associated connection state, the only way the server can do this is by referencing the name of the client.
#include stdio.h #include errno.h #include unistd.h #include stdlib.h #include sys/socket.h #include sys/un.h #define SERVER "/tmp/serversocket" #define CLIENT "/tmp/mysocket" #define MAXMSG 512 #define MESSAGE "Yow!!! Are we having fun yet?!?" int main (void) { extern int make_named_socket (const char *name); int sock; char message[MAXMSG]; struct sockaddr_un name; size_t size; int nbytes; /* Make the socket. */ sock = make_named_socket (CLIENT); /* Initialize the server socket address. */ name.sun_family = AF_LOCAL; strcpy (name.sun_path, SERVER); size = strlen (name.sun_path) + sizeof (name.sun_family); /* Send the datagram. */ nbytes = sendto (sock, MESSAGE, strlen (MESSAGE) + 1, 0, (struct sockaddr *) name, size); if (nbytes 0) { perror ("sendto (client)"); exit (EXIT_FAILURE); } /* Wait for a reply. */ nbytes = recvfrom (sock, message, MAXMSG, 0, NULL, 0); if (nbytes 0) { perror ("recfrom (client)"); exit (EXIT_FAILURE); } /* Print a diagnostic message. */ fprintf (stderr, "Client: got message: %s\n", message); /* Clean up. */ remove (CLIENT); close (sock); }
Keep in mind that datagram socket communications are unreliable. In this example, the client program waits indefinitely if the message never reaches the server or if the server's response never comes back. It's up to the user running the program to kill and restart it if desired. A more automatic solution could be to use select (the section called “Waiting for Input or Output”) to establish a timeout period for the reply, and in case of timeout either re-send the message or shut down the socket and exit.