11.16 udp_server
Function
Our final UDP function that provides a simpler
interface to getaddrinfo is udp_server.
#include "unp.h"
|
int udp_server (const char
*hostname, const char
*service, socklen_t
*lenptr);
|
Returns: unconnected socket descriptor if OK, no
return on error
|
The arguments are the same as for
tcp_listen: an optional hostname, a required service (so its port number can be bound), and
an optional pointer to a variable in which the size of the socket
address structure is returned.
Figure
11.18 shows the source code.
Figure 11.18
udp_server function: creates an unconnected socket for a
UDP server.
lib/udp_server.c
1 #include "unp.h"
2 int
3 udp_server(const char *host, const char *serv, socklen_t *addrlenp)
4 {
5 int sockfd, n;
6 struct addrinfo hints, *res, *ressave;
7 bzero(&hints, sizeof(struct addrinfo));
8 hints.ai_flags = AI_PASSIVE;
9 hints.ai_family = AF_UNSPEC;
10 hints.ai_socktype = SOCK_DGRAM;
11 if ( (n = getaddrinfo (host, serv, &hints, &res)) != 0)
12 err_quit ("udp_server error for %s, %s: %s",
13 host, serv, gai_strerror(n));
14 ressave = res;
15 do {
16 sockfd = socket (res->ai_family, res->ai_socktype, res->ai_protocol);
17 if (sockfd < 0)
18 continue; /* error - try next one */
19 if (bind (sockfd, res->ai_addr, res->ai_addrlen) == 0)
20 break; /* success */
21 Close (sockfd); /* bind error - close and try next one */
22 } while ( (res = res->ai_next) != NULL);
23 if (res == NULL) /* errno from final socket() or bind() */
24 err_sys ("udp_server error for %s, %s", host, serv);
25 if (addrlenp)
26 *addrlenp = res->ai_addrlen * return size of protocol address */
27 freeaddrinfo (ressave) ;
28 return (sockfd);
29 }
This function is nearly identical to
tcp_listen, but without the call to listen. We
set the address family to AF_UNSPEC, but the caller can
use the same technique that we described with Figure 11.14 to
force a particular protocol (IPv4 or IPv6).
We do not set the SO_REUSEADDR socket
option for the UDP socket because this socket option can allow
multiple sockets to bind the same UDP port on hosts that support
multicasting, as we described in Section 7.5. Since
there is nothing like TCP's TIME_WAIT state for a UDP socket, there
is no need to set this socket option when the server is
started.
Example: Protocol-Independent Daytime
Server
Figure
11.19 shows our daytime server, modified from Figure
11.14 to use UDP.
Figure 11.19
Protocol-independent UDP daytime server.
names/daytimeudpsrv2.c
1 #include "unp.h"
2 #include <time.h>
3 int
4 main (int argc, char **argv)
5 {
6 int sockfd;
7 ssize_t n;
8 char buff[MAXLINE];
9 time_t ticks;
10 socklen_t len;
11 struct sockaddr_storage cliaddr;
12 if (argc == 2)
13 sockfd = Udp_server (NULL, argv [1] NULL);
14 else if (argc == 3)
15 sockfd = Udp_server (argv [1], argv [2], NULL);
16 else
17 err_quit ("usage: daytimeudpsrv [ <host> ] <service or port>");
18 for ( ; ; ) {
19 len = sizeof (cliaddr) ;
20 n = Recvfrom (sockfd, buff, MAXLINE, 0, (SA *) &cliaddr, &len);
21 printf ("datagram from %s\n", Sock_ntop ((SA *) &cliaddr, len));
22 ticks = time (NULL) ;
23 snprintf (buff, sizeof (buff), "%.24s\r\n", ctime (&ticks) ) ;
24 Sendto (sockfd, buff, strlen (buff), 0, (SA *) &cliaddr, len) ;
25 }
26 }
|