2. The server receives the request, interprets it, and manipulates its resources in
11.4.9 Example Echo Client and Server
The best way to learn the sockets interface "is to study example code. Figure 11.20 shows the code for an echo client. After establishing a connection with the server, the client enters a loop that repeatedly reads a text line from standard input, sends the text line to the server, reads the echo line from the server, and prints the-result to standard output, The loop tennina\es when, f gets .encounters.BOP on ~tandard
input, either because the user typed Ctrl+D at the keyboard or. because it has exhausted the text.lines in a redirected input file.
After the loop terminates, the client closes the descriptor. This results in an EOF notification being sent to the server, whicli it detects-when it receives a return code of zero from its rio_readlineb function. After closing its descriptor, the clieht tennipates. Since the client's kernelautomatically closes all open descriptors when a'process terminates, the close in line 24 is not necessary. However, it is good programming practice to explicitly close any des9riptors that yqu have opened.
Figure 11.21 shows the main routine for theãecho server..Aftei: opening the listening descriptor, it enters anjnfinite loop. Each iteration waits for a connection request from a client, prints the domain name and port of the connected client, and then calls the echo function that services the client. After.the echo routine returns,
;Section 11.4ã TJ:\e Sockets Interface 91!5
int open_listenfd(char *port) 2 {
3 struct addrinfo hints 1 *listp, *P;
4 int listenfd, optval=1;
5
6 I* Get a list of potentiai server addresses */
7 memset(&hints, 0, sizeof(struct addrinfo));
B hints.ai_socktype = SOCK_STREAM; I* Accept connections */
' .
9 hints,.;ii_flags = AI_PA~SIVE I AI_ADDRCONFIG; /• on any IP address •/
10 hints.ai_flags I= AI_NUMERICSERV; /• ... using port number•/
11 Getaddrinfo(NULL, port, &hints, &listp);
12
13 /* Walk the list for one that we can bind to */
14 for (p = listp; p; p = p->ai_next) {
15 /*Create a socket descript~rã*/
16 if ( (listenfd = socket cp->ai_family)~ p->ai_socktype' p->ai_protocol)) < 0) 17 continu!3; /*ã-Socket failed, try the next */
. '
18 19 20 21 22 23 24 25 26
/* Eliminates 11Address already in usa11 error from bind */
• • ' l
Setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (canst void *)&optval , sizeof(int));
/* Bind the descriptor to the address */
if (bind(listenfd, p->ai_addr, p->ai_addrlen) 0) break; /* Success */
Close(listenfd); /*Bind failed, try the next*/
27 }
28 29 30 31 32 33 34 351
'
.,
36 37 38 39
40 }
/• Clean up •/
Freeaddrinfo(listp);
if ( !p) /• No addz;ess re'tll?:'n -~;
worked */
'" ,•
'-J ff)
• :i{ ,,. ' I 1 ~ h
/* Make ~t .a .. list?ning soyk~t-: rea~¥ .~o accept connection requests */
if (listen(l1stenfd, lISTEN~) < 0) {, ,
l ', ~ Jt • I '
}
C1ose(listenfd);
return -1;
'
retl!rn listenfd;:
' ! ,. ,
•)'
If f',;
---~---,,,--,., ,,,-;1,--.-~,--- code/srdcsapp.c Figure 11.19 open_listenfd! Help~r fu'nction"that'<lpens and returns a listening descriptor. It is
J r r
reeniranU1hd protocol'il)dependent'. r
'I' "
I' '
'
) I I
/.,1
r
I
"
946 Chapter 11 Network Programming
- - - codelnetp!echoclient.c
1 2
#include 11 csapp. h"
3 int main(int argc, char **argv)
4 {
5 int clientfd;
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 }
char *host, *port, buf[MAXLINE];
rio_t rio;
if (argc !• 3) {
}
fprintf(stderr, "usage: %s <host> <port>\n", argv [O]);
exit(O);
host = argv [1] ; port = argv [2) ;
clientfd = Open_clientfd(host, port);
Rio_readinitb(&rio, clientfd);
while (Fgets(buf, MAXLINE, stdin) != NULL) { Rio_writen(clientfd, buf, strlen(buf));
Rio_readlineb(&rio, buf, MAXLINE);
Fputs(buf, stdout);
}
Close(clientfd);
exit(O);
- - - code/netp/echoclient.c Figure 11.20 Echo client main routine.
the main routine closes the connected descriptor. Once the client and server have closed their respective descriptors, the connection is terminated.
The clientaddr variable in line 9 is a socket address structure that is passed to accept. Before accept returns, it fills in clientaddr with the socket address of the client on the other end of the connection. Notice how we declare clientaddr as type struct sockaddr _storage rather than struct sockaddr _in. By defini- tion, the sockaddr _storage structure is large enough to hold any type of socket address, which keeps the code protocol-independent.
Notice that our simple echo server can only handle one client at a time.
A server of this type that iterates through clients, one at a time, is called an iterative server. In Chapter 12, we will learn how to build more sophisticated concurrent servers that can handle multiple clients simultaneously.
Finally, Figure 11.22 shows the code for the echo routine, which repeatedly reads and writes lines of text until the rio_readlineb function encounters EOF in line 10.
Section 11 .4 The Sockets Interface 947 - - - codelnetp/echoserveri.c
1 #include "csapp. h 11 2
3 void echo(int connfd);
4
5 int main(int argc, char **argv)
6 {
int listenfd, connfd;
socklen_t clientlen;
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 2~ã,, 26
struct sockaddr_storage clientaddr; /* Enough space for any address •/
char clie~t_hostname[MAXLINE], client_port[MAXLINE];
if (argc != 2) {
}
fprintf (stderr, "usage: %s <port>\n 11, argv [O]) ; exit(O);
listenfd = ,9pen_;Lif.ltenfd(argv[1]);
while (1}( f. ,1
clie~tlen = sizeof(struct1sockaddr_storage);
connfd = Accept(listenfd', cSiJ1;i.)&clientaddr, &ciientle~);
Getnameinfo((SA *) &clientaddr, clientlen, client_hostname, MAXLINE, client_port, MAXLINE, O);
printf(11Connected to (%s, %s)\n11, client_hostname, _client_port);
echo(connfd);
2'7
28 '1'ã}
Close(cqnnfd);
} . .,
e?Cit(O) i
'[11
('\_ \ l
.. ' II
- - - . - - - , , - - - , - - - , - - - , - - - - ; - - - , - l code!netp/echoserveri.c Figure 11.21 lterative'ecHo server n'lain routine.
---~~---~ code!netplecho.c
1 2 3 4
#inClude "csapp.h11 void echo(int connfd) {
5 size_t n;
6 char buf [MAXLINEJli~
7 rio_t rio;
8
9 Rio_readlnitb(&rio, cOnnfd);
10 while((n = Rio_read~ineb(&rio, buf, MAXLINE)) !~ O) { 11 printf("server received %d bytes\n", (int)?J-);
12 Rio_writen(cbnnfd, buf, n); [~
13 }
14 " j
I '
---~---~--~---~-=~-...,r-'~-~.code/netp/echo.c
Figure H.22 echo • furif'tion that reads •l)p echoesãtext lines. ' ' ,.f . I
• v ~ t' J I
I ,,
i I
I
I I
948 Chapter 11 Network Programming
.,. ~' ~ ~ ~~ ""-.~ ~ ã•"'
Aside What does EOF on a oonnection mean?
•
ã.w~. '~~ '>!' ~
The.idea of EbF is often confusing to '.students, especihlly in Jhe'context of Internet connections. First,.' we ne(\d to understand tharthere is no s~ch.\hit\g as an•EOF character. Rathel\ EOF•is a condition that , is detected by the kernel. An application}inds out about the EOF condition when it re~ei~es,a;iercl '
return code froin the rea'd fuifcticih. For dislj: files, EOF qi;curs whe,/lãthe current file p6sifiot exceeds the file length. For Internet connections, 'EOf _occurs wlien' ~ process closes its ,end of<the connection.
The process at the other end of the connection detects the EOF when it-attemptS"t<l' read past the last l;>yte in' the stre<J.m. " '. • • ' '• "
""-""'''" 'ã"'ã~ ""' ,,,...,,, ,,,,,,.;,,, "' ,,,,,._,,,., ""'""""'~;,.~~",;:;: ~W.,, ~- "" ei ,,;;.._,,,,,.._,., ,)s.IA~,,,,,,,,, "" ,,.,. ::_!