Udp socket bind example
If the local address was constructed using getaddrinfo then the memory occupied by the address list can now be released:. If the address list has been searched or filtered then take care that it is the head of the list that is released, not the address that you have chosen to use.
Datagrams can be received using any function that is capable of reading from a file descriptor, however if you are listening for unsolicited datagrams as in this example then you will normally want to know where each datagram originated from so that it can be replied to. This information is provided by the functions recvfrom and recvmsg.
Of these recvmsg is the more flexible option, but at the cost of a significantly more complex interface. Details for each function are given below. Regardless of which function you choose you will need to supply a buffer to receive the data. If this is too small to accommodate a complete datagram then any excess is discarded. That means you need not be concerned about tracking datagram boundaries, because the first byte returned by a read operation will always be the start of a datagram.
However it does raise two issues: UDP-based application-layer protocols often limit the size of datagram that can be sent in order to provide an solution to the first issue. For DHCP the limit defaults to bytes, but a larger value can be negotiated if both parties are willing to support it. In the absence of such guidance it is necessary to consider what the transport, network and link layer protocols are likely to support. However, the largest payload that an implementation is required to support is bytes for IPv4 and bytes for IPv6.
On an Ethernet with the standard MTU of bytes, the largest payload that can be sent without fragmentation is bytes. On this basis, bytes would be a reasonable choice if you have no reason to believe that a larger buffer is needed or that a smaller buffer would suffice.
Alternatively, truncation can be detected when using any of the available functions by providing a buffer that is one byte longer than the largest payload that you actually wish to receive, then interpreting a full buffer as a truncated datagram. To call recvfrom you need a buffer for the datagram and a buffer for the remote address:.
The fourth argument is for specifying flags which modify the behaviour of recvfrom , none of which are needed in this example. The value returned by recvfrom is the number of bytes received, or -1 if there was an error. Truncation is detected in this example using the technique described above of providing a slightly over-sized datagram buffer.
To call recvmsg , in addition to buffers for the datagram and remote address you must also construct an iovec array and a msghdr structure:. In this example the entire payload is stored in a single buffer, therefore only one array element is needed.
The msghdr structure exists to bring the number of arguments to recvmsg and sendmsg down to a managable number. On entry to recvmsg it specifies where the source address, the datagram payload and any ancillary data should be stored.
In this example no ancillary data has been requested, therefore no provision has been made for receiving any. Instead you must pass them using the third argument to recvmsg which is zero in this example.
When listening for a reply to a datagram that you have sent then three of the four steps listed above may be omitted:. When exchanging many datagrams from a particular remote host it may be beneficial for a UDP socket to be connected to that host. This removes the need for the remote address to be explicitly checked every time a datagram is received, and for the address to be specified every time one is sent. The connection is made using the connect function:.
This is superficially identical to the call that would be made to establish a TCP connection, however unlike TCP there is no handshake. This has two notable consequences:. With UDP, our sockets are connectionless. Hence, we can send messages immediately. Since we do not have a connection, the messages have to be addressed to their destination.
Instead of using a write system call, we will use sendto , which allows us to specify the destination. The address is identified through the sockaddr structure, the same way as it is in bind and as we did when using connect for TCP sockets. The first parameter, socket , is the socket that was created with the socket system call and named via bind. The second parameter, buffer , provides the starting address of the message we want to send. The flags parameter is 0 and not useful for UDP sockets.
As with bind , the final parameter is simply the length of the address structure: The server's address will contain the IP address of the server machine as well as the port number that corresponds to a socket listening on that port on that machine. The IP address is a four-byte 32 bit value in network byte order see htonl above. In most cases, you'll know the name of the machine but not its IP address.
An easy way of getting the IP address is with the gethostbyname library libc function. Gethostbyname accepts a host name as a parameter and returns a hostent structure:. There may be more than one IP addresses for a host. In practice, you should be able to use any of the addresses or you may want to pick one that matches a particular subnet. We'll be lazy here and just use the first address in the list. For example, suppose you want to find the addresses for google.
The code will look like this:. Here's the code for sending a message to the address of a machine in host. The variable fd is the socket which was created with the socket system call. With TCP sockets, a server would set up a socket for listening via a listen system call and then call accept to wait for a connection. A server can immediately listen for messages once it has a socket.
We use the recvfrom system call to wait for an incoming datagram on a specific transport address IP address and port number. The first parameter, socket is a socket that we created ahead of time and used bind. The port number assigned to that socket via the bind call tells us on what port recvfrom will wait for data.
The incoming data will be placed into the memory at buffer and no more than length bytes will be transferred that's the size of your buffer. We will ignore flags here.
You can look at the man page for recvfrom for details on this. This parameter allows us to process out-of-band data, peek at an incoming message without removing it from the queue, or block until the request is fully satisfied.
We can safely ignore these and use 0. If you do not care to identify the sender, you can set both of these to zero but you will then have no way to reply to the sender. Let's examine a simple server. We'll create a socket, bind it to all available IP addresses on the machine but to a specific port number. Then we will loop, receiving messages and printing their contents. We now have a client sending a message to a server. What if the server wants to send a message back to that client?
There is no connection so the server cannot just write the response back. Fortunately, the recvfrom call gave us the address of the server.
It was placed in remaddr:. The server can use that address in sendto and send a message back to the recipient's address. Close the socket With TCP sockets, we saw that we can use the shutdown system call to close a socket or to terminate communication in a single direction. Since there is no concept of a connection in UDP, there is no need to call shutdown. However, the socket still uses up a file descriptor in the kernel, so we can free that up with the close system call just as we do with files.
For questions or comments about this site, contact Paul Krzyzanowski, gro. The entire contents of this site are protected by copyright under national and international law.