Assuming that the server and client have established a connection, the server calls close and sends a fin segment to the client (which does not necessarily send the fin segment, after that), when the server can no longer send and receive data through the socket. When the client invokes read, if the fin segment returns 0, but the client can write to the server at this time, the write call is responsible for sending the data to the TCP send buffer to successfully return, so there is no error, and the server receives the data After answering a RST segment, indicating that the server has not been able to receive data, the connection reset, the client received the RST segment can not immediately notify the application layer, only to save this state in the TCP protocol layer. If the client calls write data to the server again, because the TCP protocol layer is already in the RST state, the data is not emitted, but a sigpipe signal is sent to the application layer, and the default processing action of the sigpipe signal is the termination procedure.
Sometimes the code needs to call write several times in a row, it may not be too late to call read to know that the other side has closed the connection is sigpipe signal terminated, which requires the initialization of the call sigaction processing sigpipe signal, for this signal processing we usually ignore can, Signal (Sigpipe, sig_ign); If the sigpipe signal does not cause the process to exit abnormally, write returns-1 and errno is epipe.
#include <unistd.h>
int close (int fd);
Close closes the two directions of its own data transfer.
#include <sys/socket.h>
int shutdown (int sockfd, int how);
Shutdown can choose to close a direction or turn off two directions at the same time, shutdown how = 1 or how = 2 (SHUT_WR or SHUT_RDWR) to ensure that the peer receives an EOF character (that is, a fin segment is sent), regardless of whether the other processes This socket has been opened. Close does not guarantee that the fin segment will be sent only if the reference count of a SOCKFD is 0,close, otherwise the reference count will only be reduced by 1. That is, close does not send a fin segment until all processes (possibly fork multiple child processes have opened the socket) have closed this socket.
So if it's called shutdown how = 1, it means that writing to a socket that has received the fin is allowed, and receiving the fin segment only means that the other person is not sending the data, but the other person can read the data, allowing the other to read the remaining data in the buffer.
The following uses shutdown to modify the client program, based on the previous modified client program using the Select function, a small part:
if (Fd_isset (Fd_stdin, &rset))
{
if (fgets (sendbuf, sizeof (SENDBUF), stdin) = NULL)
{
stdineof = 1 ; Indicates that you have entered
/* Closes the write end of the sock and can receive data, adding a fin segment to the end of the sock buffer
/shutdown (sock, SHUT_WR);
}
else
{
writen (sock, SendBuf, strlen (SendBuf));
memset (sendbuf, 0, sizeof (SENDBUF));
}
To test the effect we want, we need to sleep (4) after the 134 lines of the server-side program after the SELECT function has been modified, that is, the writen; The purpose is to receive the client data not immediately back to the back, sleep 4s after the client has closed the connection to send data.
Run the server-side program first, then run the client program, in the client standard input, quickly type two lines: aaaaa\n bbbbb\n then press ctrl+d that fgets will return null, and then call shutdown close the write end, although the server-side delay to send data, At this point the client write end has been closed, but can still read back to the back of the data, the server end to get a fin segment, read returned 0, print output client close, and close (conn); And the client after reading the server back to shoot back two data, read also returned 0, so print server connect Close,break exit cycle, the process smoothly exit. The output from the following can also be seen, because of the delay of the relationship, so do not launch a row as before, back to shoot a row.
simba@ubuntu:~/documents/code/linux_programming/unp/socket$./echoser_select
Recv Connect ip=127.0.0.1 port=54010
Fdsgfgd
Gfedg
Client close.
..........................
simba@ubuntu:~/documents/code/linux_programming/unp/socket$./echocli_select_shutdown
Local ip=127.0.0.1 port=54010
Fdsgfgd
Gfedg
Fdsgfgd
Gfedg
Server Connect Close
If we change the shutdown in the client program to close, then when the server sends the data to the client after the delay, the client's read and write ends are closed, and the first AAAAA will return a RST segment, according to the previous article, Sending a BBBBB directly generates a sigpipe signal, which terminates the process by default, but because we have set the Ignore Sigpipe signal, the server-side process will not be terminated, but the client will also make an error because it is back at the start of the while loop, When the select blocks wait, the read end of the socket is found to be closed, so no longer cares about the readable event, and the Select returns-1 and the error code is Ebadf:bad File descriptor.