ptg10805159
Section 16.5 Data Transfer 621
int sockfd, err;
struct sigaction sa;
if (argc != 2)
err_quit("usage: ruptime hostname");
sa.sa_handler = sigalrm;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
if (sigaction(SIGALRM, &sa, NULL) < 0)
err_sys("sigaction error");
memset(&hint, 0, sizeof(hint));
hint.ai_socktype = SOCK_DGRAM;
hint.ai_canonname = NULL;
hint.ai_addr = NULL;
hint.ai_next = NULL;
if ((err = getaddrinfo(argv[1], "ruptime", &hint, &ailist)) != 0)
err_quit("getaddrinfo error: %s", gai_strerror(err));
for (aip = ailist; aip != NULL; aip = aip->ai_next) {
if ((sockfd = socket(aip->ai_family, SOCK_DGRAM, 0)) < 0) {
err = errno;
}else {
print_uptime(sockfd, aip);
exit(0);
}
}
fprintf(stderr, "can’t contact %s: %s\n", argv[1], strerror(err));
exit(1);
}
Figure 16.19 Client command using datagram service
The main function for the datagram-based client is similar to the one for the
connection-oriented client, with the addition of installing a signal handler forSIGALRM.
We use thealarmfunction to avoid blocking indefinitely in the call torecvfrom.
With the connection-oriented protocol, we needed to connect to the server before
exchanging data. The arrival of the connect request was enough for the server to
determine that it needed to provide service to a client. But with the datagram-based
protocol, we need a way to notify the server that we want it to perform its service on
our behalf. In this example, we simply send the server a 1-byte message. The server
will receive it, get our address from the packet, and use this address to transmit its
response. If the server offered multiple services, we could use this request message to
indicate the service we want, but since the server does only one thing, the content of the
1 - byte message doesn’t matter.
If the server isn’t running, the client will block indefinitely in the call torecvfrom.
With the connection-oriented example, theconnectcall will fail if the server isn’t
running. Toavoid blocking indefinitely, we set an alarm clock beforecallingrecvfrom.