20.3 Simple-Request Protocols

Team-FLY

20.3 Simple-Request Protocols

A protocol is a set of rules that endpoints follow when they communicate. Simple request [110] is a client-server protocol in which a client sends a request to the server but expects no reply. Figure 20.2 shows a schematic of the steps involved in implementing a simple-request protocol using UICI UDP.

Figure 20.2. Interaction of a UICI UDP client and server using a simple-request protocol.

graphics/20fig02.gif

Programs 20.1 and 20.2 illustrate the simple-request protocol. The server creates a UDP socket associated with a well-known port ( u_openudp ) and then waits for a request from any sender ( u_recvfrom ). The server blocks on u_recvfrom until receiving a message. The server responds by writing the remote host name and received message to standard output and then waits in a loop for another message.

Exercise 20.2

Under what conditions does the server of Program 20.1 exit?

Answer:

The server exits if it is given the wrong number of command-line arguments or if u_openudp fails. After that, the server will not exit unless it receives a signal. No transmission by a client can cause the server to exit.

Program 20.1 server_udp.c

A server program writes sender information and the received message to its standard output .

 #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 communication endpoint */    if ((requestfd = u_openudp(port)) == -1) {       perror("Failed to create UDP endpoint");       return 1;    }    for ( ; ; ) {                                 /* process client requests */       bytesread = u_recvfrom(requestfd, buf, BUFSIZE, &senderinfo);       if (bytesread < 0) {          perror("Failed to receive 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 reply to standard output");       }    } } 

The client of Program 20.2 creates a UDP socket by calling u_openudp with a parameter of 0. In this case, u_openudp does not bind the socket to a port. The client initiates a request by calling u_sendtohost , specifying the host name and the well-known port of the server. Since the client has not bound its socket to a port, the first send on the socket causes the network subsystem to assign a private port number, called an ephemeral port , to the socket. The client of Program 20.2 sends a single request and then calls r_close to release the resources associated with the communication endpoint. Notice that the server does not detect an error or end-of-file when the client closes its socket, because there is no connection between the endpoints in the two applications.

Program 20.2 client_udp.c

A client program that sends a request containing its process ID .

 #include <limits.h> #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[]) {    ssize_t byteswritten;    char request[BUFSIZE];    int requestfd;    int rlen;    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 */    rlen = strlen(request);     /* use  simple-request protocol to send a request to (server, serverport) */    byteswritten = u_sendtohost(requestfd, request, rlen, argv[1], serverport);    if (byteswritten == -1)       perror("Failed to send");    if (r_close(requestfd) == -1  byteswritten == -1)       return 1;    return 0; } 
Exercise 20.3

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

 server_udp 20001 

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

 client_udp yourhost 20001 

Observe the assignment of ephemeral port numbers . What output does the server produce? How about the clients?

Answer:

Ephemeral ports are assigned in a system-dependent way. If all goes well, the clients do not produce output. For each message sent by a client, the server produces a line of output. If a client with process ID 2345 runs on machine myhost and uses ephemeral port 56525, the following message appears on standard output of the server.

 port number is 56525 on host myhost[2345] 

Figure 20.3 uses a time line to depict a sequence of events produced by the simple-request protocol. The diagram assumes that the client and the server have created their communication endpoints before the time line starts. Black dots represent event times relative to the same clock. For functions, the dots indicate the times at which the function returns to the caller. Remember that the clock times observed by the client and server are usually not synchronized unless the client and server are on the same machine.

Figure 20.3. Time line illustrating the sequence of events for the simple-request protocol.

graphics/20fig03.gif

The u_sendtohost function is nonblocking in the sense that it returns after copying the message to the network subsystem of the local machine. The u_recvfrom function blocks until it receives a message or an error occurs. The u_recvfrom function restarts itself after receiving a signal, in contrast to the underlying library function recvfrom , as explained in Section 20.7.

Exercise 20.4

Run Program 20.2 without starting the corresponding server. What happens?

Answer:

UDP does not determine whether the receiver host and its server program exist, so the client cannot detect whether the server has errors. A client generates an error only if it cannot resolve the server host name.

Exercise 20.5

Figure 20.3 assumes that the server has been started before the client and is ready to receive when the message arrives. What happens if the client's message arrives before the server has created its communication endpoint? What happens if the client's message arrives after the server has created its endpoint but before it has called u_recvfrom?

Answer:

If the client's message arrives before the server has created its endpoint, the message is lost. In the second case, the result depends on how much buffer space has been allocated for the endpoint and how many messages have already arrived for that endpoint. If the endpoint's buffer has room, the network subsystem of the server host stores the message in the endpoint's buffer. The server calls u_recvfrom to remove the message. Communication is an asynchronous process, and a major role of the communication endpoint is for the network and I/O subsystems to provide buffering for incoming messages until user processes are ready for them.

Exercise 20.6

Modify the client in Program 20.2 to send 1000 requests, and modify the server in Program 20.1 to sleep for 10 seconds between the u_openudp call and the while loop. Start the server and immediately start the client. How many messages are received by the server?

Answer:

The answer depends on the size of the endpoint buffers. You might see about 100 messages delivered. If all of the messages are delivered, try increasing the number of messages sent by the client to 10,000.

Figure 20.3 illustrates the ideal scenario, in which the client's message successfully arrives at the server and is processed . In reality, today's network infrastructure provides no guarantee that all messages actually arrive . Figure 20.4 illustrates a scenario in which the message is lost because of a network error. The server has no knowledge of the message's existence.

Figure 20.4. Time line illustrating a lost request for the simple-request protocol.

graphics/20fig04.gif

Exercise 20.7

Draw a timing diagram similar to those of Figures 20.3 and 20.4 that illustrates a scenario in which the server receives a client request and then crashes before processing the request.

Answer:

Relabel the second event dot on the server's time line in Figure 20.3 as a crash event.

Team-FLY


Unix Systems Programming
UNIX Systems Programming: Communication, Concurrency and Threads
ISBN: 0130424110
EAN: 2147483647
Year: 2003
Pages: 274

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net