Unix™ Systems Programming [Electronic resources] : Communication, Concurrency, and Threads نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Unix™ Systems Programming [Electronic resources] : Communication, Concurrency, and Threads - نسخه متنی

Prentice Hall

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید










20.4 Request-Reply Protocols


In the simple-request protocol, the client cannot distinguish the scenario of Figure 20.3 from those of Figure 20.4 and Exercise 20.7 because it does not receive an acknowledgment of its request or any results produced by the request. A request-reply protocol handles this problem by requiring that the server respond to the client. Figure 20.5 shows a sequence of steps, using UICI UDP, to implement a simplified request-reply protocol. If no errors occur, the server's reply message notifies the client that the transmission was successful. The server reply message can contain actual results or just a flag reporting the status of the request.


Figure 20.5. Sequence of steps in an error-free request-reply protocol.


Program 20.3 shows the server-side implementation of the request-reply protocol of Figure 20.5. The server receives a request and uses u_gethostinfo to extract the identity of the client. After printing the client's name and request to STDOUT_FILENO, the server uses u_sendto with the u_buf_t structure (senderinfo) returned from u_recvfrom to respond to that client. The UICI UDP u_sendto function uses the u_buf_t structure as the destination address to ensure that the reply is directed to the correct client. The server shown here replies with a copy of the request it received.

Exercise 20.8

An important consideration in writing a server is to decide which conditions should cause the server to exit, which conditions should be ignored, which conditions should be logged and which conditions should trigger a recovery procedure. The server of Program 20.3 never exits on its own once its port is bound to the socket. You can terminate the server by sending it a signal. Under what conditions would it be reasonable for a server such as an ftp server to exit?

Answer:

You could argue that an ftp server should never exit because it should be running at all times. Certainly, an error caused by a client should not terminate the server. Even if system resources are not available to handle a connection, the problem might be temporary and the server would continue to work after the problem is resolved. Errors should be logged so the administrator has a record of any problems.

Program 20.3 server_udp_request_reply.c

A server program that implements a request-reply protocol.


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "restart.h"
#include "uiciudp.h"
#define BUFSIZE 1024
int main(int argc, char *argv[]) {
char buf[BUFSIZE];
ssize_t bytesread;
char hostinfo[BUFSIZE];
u_port_t port;
int requestfd;
u_buf_t senderinfo;
if (argc != 2) {
fprintf(stderr, "Usage: %s port\n", argv[0]);
return 1;
}
port = (u_port_t) atoi(argv[1]); /* create UDP endpoint for port */
if ((requestfd = u_openudp(port)) == -1) {
perror("Failed to create UDP endpoint");
return 1;
}
for ( ; ; ) { /* process client requests and send replies */
bytesread = u_recvfrom(requestfd, buf, BUFSIZE, &senderinfo);
if (bytesread == -1) {
perror("Failed to receive client request");
continue;
}
u_gethostinfo(&senderinfo, hostinfo, BUFSIZE);
if ((r_write(STDOUT_FILENO, hostinfo, strlen(hostinfo)) == -1) ||
(r_write(STDOUT_FILENO, buf, bytesread) == -1)) {
perror("Failed to echo client request to standard output");
}
if (u_sendto(requestfd, buf, bytesread, &senderinfo) == -1) {
perror("Failed to send the reply to the client");
}
}
}

Program 20.4 shows a client that uses the request-reply protocol of Figure 20.5. The request is just a string containing the process ID of the requesting process. The protocol is implemented in the request_reply function shown in Program 20.5. The client sends the initial request and then waits for the reply. Since anyone can send a message to an open port, the client checks the host/port information against the sender information supplied in senderinfo to make sure that it received the reply from the same host that it sent to.

Program 20.4 client_udp_request_reply.c

A client program that sends a request containing its process ID and reads the reply.


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "restart.h"
#include "uiciudp.h"
#define BUFSIZE 1024
int request_reply(int requestfd, void* request, int reqlen,
char* server, int serverport, void *reply, int replen);
int main(int argc, char *argv[]) {
ssize_t bytesread, byteswritten;
char reply[BUFSIZE];
char request[BUFSIZE];
int requestfd;
u_port_t serverport;
if (argc != 3) {
fprintf(stderr, "Usage: %s servername serverport\n", argv[0]);
return 1;
}
serverport = (u_port_t) atoi(argv[2]);
if ((requestfd = u_openudp(0)) == -1) { /* create unbound UDP endpoint */
perror("Failed to create UDP endpoint");
return 1;
}
sprintf(request, "[%ld]\n", (long)getpid()); /* create a request */
/* use request-reply protocol to send a message */
bytesread = request_reply(requestfd, request, strlen(request)+1,
argv[1], serverport, reply, BUFSIZE);
if (bytesread == -1)
perror("Failed to do request_reply");
else {
byteswritten = r_write(STDOUT_FILENO, reply, bytesread);
if (byteswritten == -1)
perror("Failed to echo server reply");
}
if ((r_close(requestfd) == -1) || (bytesread == -1) || (byteswritten == -1))
return 1;
return 0;
}

Exercise 20.9

What happens when the scenario of Figure 20.4 occurs for the request-reply protocol of Figure 20.5?

Answer:

The client hangs indefinitely on the blocking u_recvfrom call.

Program 20.5 request_reply.c

Request-reply implementation Aassumes error-free delivery.


#include <sys/types.h>
#include "uiciudp.h"
int request_reply(int requestfd, void* request, int reqlen,
char* server, int serverport, void *reply, int replen) {
ssize_t nbytes;
u_buf_t senderinfo;
/* send the request */
nbytes = u_sendtohost(requestfd, request, reqlen, server, serverport);
if (nbytes == -1)
return (int)nbytes;
/* wait for a response, restart if from wrong server */
while ((nbytes = u_recvfrom(requestfd, reply, replen, &senderinfo)) >= 0 )
if (u_comparehost(&senderinfo, server, serverport)) /* sender match */
break;
return (int)nbytes;
}

Exercise 20.10

Compile Programs 20.3 and 20.4. Start the server on one machine (say, yourhost) with the following command.


server_udp_request_reply 20001

Run clients on different hosts by executing the following on several machines.


client_udp_request_reply yourhost 20001

Put timing statements in Example 9.8.) Run the client program several times. Do any of the instances hang? Under what circumstances would you expect the client to hang?

Answer:

The client blocks indefinitely on u_recvfrom if it does not receive the reply from the server. Modern networks have become so reliable that if the client and server are running on the same local area network (LAN), it is unlikely that either the request or the reply messages will be lost because of errors along particular wires. In high-congestion situations, packets may be dropped at LAN switches. If many clients are making simultaneous requests, the network subsystem of the server host might discard some packets because the communication endpoint's buffers are full. Messages from clients and servers on different LANs generally follow paths consisting of many links connected by routers. Congested routers drop messages that they can't handle, increasing the likelihood that a message is not delivered.

Exercise 20.11

Figure 20.6 illustrates the timing for the request-reply protocol when there are no errors. When errors are possible, the nine events listed in the following table can occur in various orders.

event

description

A

client sends request message

B

server receives request message

C

server processes request

D

server sends reply message

E

client receives reply message

F

request message is lost

G

reply message is lost

H

client crashes

I

server crashes

The event sequence ABCDE represents the scenario of Figure 20.6. For the five event sequences listed below, state whether each represents a physically realizable scenario. If the scenario is realizable, explain the outcome and draw a timing diagram similar to that shown in Figure 20.6. If the scenario is not realizable, explain why.

  1. ABCED

  2. ABCDG

  3. ABCI

  4. ABCGD

  5. ABCDIE


What other event sequences represent possible scenarios for request-reply?

Answer:

  1. ABCED is not realizable, since the client cannot receive a message before the server sends it. This assumes that no other process on the server host has guessed the ephemeral port number used by the client and sent a bogus reply. It also assumes that another host has not spoofed the IP address of the server. We do not consider these scenarios here.

  2. ABCDG is realizable and represents a situation in which the client does not receive a response even though the server has processed the request.

  3. ABCI is realizable and represents a situation in which the server receives the request and processes it but crashes before it sends the response.

  4. ABCGD is not realizable, since a message cannot be lost before it is sent.

  5. ABCDIE is possible. If the server crashes after it sends the reply, the reply can still be received.


Many other event sequences represent realizable scenarios.


Figure 20.6. Timing diagram of the request-reply protocol.



    / 276