5.13 SIGPIPE Signal
What happens if the client ignores the error return from readline and writes more data to the server? This can happen, for example, if the client needs to perform two writes to the server before reading anything back, with the first write eliciting the RST.The rule that applies is: When a process writes to a socket that has received an RST, the SIGPIPE signal is sent to the process. The default action of this signal is to terminate the process, so the process must catch the signal to avoid being involuntarily terminated.If the process either catches the signal and returns from the signal handler, or ignores the signal, the write operation returns EPIPE.
A frequently asked question (FAQ) on Usenet is how to obtain this signal on the first write, and not the second. This is not possible. Following our discussion above, the first write elicits the RST and the second write elicits the signal. It is okay to write to a socket that has received a FIN, but it is an error to write to a socket that has received an RST.
To see what happens with SIGPIPE, we modify our client as shown in Figure 5.14.
Figure 5.14 str_cli that calls writen twice.
tcpcliserv/str_cli11.c
1 #include "unp.h"
2 void
3 str_cli(FILE *fp, int sockfd)
4 {
5 char sendline [MAXLINE], recvline [MAXLINE];
6 while (Fgets(sendline, MAXLINE, fp) != NULL) {
7 Writen(sockfd, sendline, 1);
8 sleep(1);
9 Writen(sockfd, sendline + 1, strlen(sendline) - 1);
10 if (Readline(sockfd, recvline, MAXLINE) == 0)
11 err_quit("str_cli: server terminated prematurely");
12 Fputs(recvline, stdout);
13 }
14 }
79 All we have changed is to call writen two times: the first time the first byte of data is written to the socket, followed by a pause of one second, followed by the remainder of the line. The intent is for the first writen to elicit the RST and then for the second writen to generate SIGPIPE.If we run the client on our Linux host, we get:
linux % tcpclill 127.0.0.1 | |
hi there | we type this line |
hi there | this is echoed by the server |
here we kill the server child | |
bye | then we type this line |
Broken pipe | this is printed by the shell |