When the server closes a connection, if the client sends data. According to the TCP protocol, an rst response is received. When the client sends data to the server, the system sends a sigpipe signal to the process, telling the process that the connection has been disconnected, do not write any more.
Or when a process writes data to a socket that has received the rst, the kernel sends a sigpipe signal to the process. The default degree for this signal is to terminate the process, so the process must capture it to avoid reluctance to terminate.
According to the default signal processing rules, the default operation of the sigpipe signal is terminate (termination, exit), so the client will exit. If you do not want the client to exit, set sigpipe to sig_ign.
For example, signal (sigpipe, sig_ign );
At this time, sigpipe is handed over to the system for processing.
If fork is used on the server, it is necessary to collect the garbage process to prevent the generation of the zombie process. You can handle it like this:
Signal (sigchld, sig_ign );
It is handed to system init for recovery.
Here, sub-processes will not generate zombie processes.
When writing a socket program in Linux, if you try to send it to a disconnected socket, the underlying layer will throw a sigpipe signal.
The default processing method for this signal is to exit the process, which is not what we expect most of the time. Therefore, we need to reload the processing method of this signal. Call the following code to safely shield sigpipe:
Struct sigaction SA;
SA. sa_handler = sig_ign;
Sigaction (sigpipe, & SA, 0 );
The signal handle set by signal can only be used once. After the signal is captured once, the signal handle will be restored to the default value.
The signal handle set by sigaction can be valid until you change its settings again.
Struct sigaction action;
Action. sa_handler = handle_pipe;
Sigemptyset (& Action. sa_mask );
Action. sa_flags = 0;
Sigaction (sigpipe, & Action, null );
Void handle_pipe (INT sig)
{
// No processing is required.
}
RST refers to "reset", which is a TCP segment issued by TCP in certain errors. There are three conditions that can generate the RST:
1), Syn arrives at a port, but there is no server being monitored on this port.
2), TCP wants to cancel an existing connection
3), TCP receives a shard on a connection that does not exist at all.
1. The connect function returns an error econnrefused:
If the response to the customer's SYN is RST, it indicates that the server host has no process waiting to connect to it on the port we specified (for example, the server process may not be started ), this is called hard error. Once the customer receives the rst, the error econnrefused will be returned immediately.
TCP maintains two queues for the listener interface. The sum of the two queues cannot exceed the second backlog parameter of the listen function.
When a customer SYN arrives, if both queues are full, TCP ignores this shard and does not send rst. this is because: this situation is temporary. The customer TCP will resend the SYN and expect to find idle entries in the queue soon. If the TCP server sends an rst, the client connect function will immediately send an error, forcing the application process to handle this situation, rather than letting the TCP normal retransmission mechanism handle it. In addition, the customer cannot distinguish the two situations: As a SYN response, RST indicating "No server on this port" and RST indicating "a server on this port but its queue is full.
Posix.1g allows two Processing Methods: Ignore the new SYN or respond to an rst for this syn. Historically, All implementations originating from Berkeley ignore the new syn.
2. if the server is killed to process the sub-process of the client, after the process exits, close all file descriptors it opens. At this time, when the server TCP receives data from the client, the process of the socket interface that was previously opened has been terminated, so it responds with RST.
Frequently encountered problems:
If the return value of the read and write functions is not determined, the server does not know whether the server has responded to the RST. If the client performs a write operation on the interface that has received the rst, the kernel sends a sigpipe signal to the process. The default action of this signal is to terminate the process. Therefore, the process must capture it to avoid being aborted reluctantly.
Whether the process captures the signal and returns it from its signal processing program or ignores the signal, the write operation returns an epipe error.
3. Restart After the server host crashes
If a connection is established between the server host and the client crashes, if the client sends data to the server and the server crashes, the client cannot respond to the ACK, and the client TCP will continuously re-transmit data in different segments, try to receive an ACK from the server. If the server crashes all the time, the client will find that the server has crashed or the destination is inaccessible, but it may take a long time. If the server restarts before the client detects a crash, the TCP of the server loses all the connection information before the crash, so the TCP of the server returns the response to the received customer data in RST segments.
Ii. Socket Recv:
For TCP non-blocking socket, The Recv returned value is =-1, but errno = eagain, which indicates that there is no data in the corresponding Socket buffer when the Recv is executed, and Recv should be continued.
[If no messages are available at the socket and o_nonblock is not set on the socket's file descriptor,
Recv() Shall block until a message arrives. If no messages are available at the socket and o_nonblock is set on the socket's file descriptor,
Recv() Shall fail and setErrnoTo [eagain] or [ewouldblock].]
For UDP Recv, it should be read until Recv () =-1 & errno = eagain, indicating that all data packets in the buffer are read.
When receiving data, the error message "resource temporarily unavailable" is often reported. The errno code is 11 (eagain ). This indicates that you have called the blocking operation in non-blocking mode. If the operation is not completed, this error is returned. This error will not damage the synchronization of the socket, the next cycle is followed by Recv. For a non-blocking socket, eagain is not an error. On VxWorks and windows, eagain is named ewouldblock. In fact, this is not an error, but an exception.
while (res != 0) { //len = recv(sockfd, buff, MAXBUF, 0);
len = recv(sockfd, buff, 5, 0); if (len < 0 ) { if(errno == EAGAIN) { printf("RE-Len:%d errno EAGAIN\n", len); continue;/*return 12;*//* The socket's file descriptor is marked o_nonblock and no data is waiting to be stored Ed; or MSG_OOB Is set and no out-of-band data is available and either the socket's file descriptor is marked o_nonblock or the socket does not support blocking to await out-of-band data. */
}
if (errno == EINTR)
continue;
perror("recv error\n"); break; } else if (len > 0) { printf("Recved:%s, and len is:%d \n", buff, len); len = send(sockfd, buff, len, 0); /* if the client socket was closed and the socketfd here in kernel has set the status as RST this process will recv a SIGPIPE, and the process will exit if we don't handle it to SIGING */ if (len < 0) { perror("send error"); return -1; } memset(buff, 0, MAXBUF); continue; } else { //==0 printf("Disconnected by peer!\n"); res = 0;
return res; } }
|
Note:
Accetp () is a slow system call. When a signal is generated, the call is interrupted and the errno variable is set to eintr. In this case, you should call accept () again ().
Therefore, we should use this method:
while(1) { if ( (connfd = accept(....)) == -1 ) { if (errno == EINTR) continue; perror("accept()"); exit(1); }
/* do sth with "connfd" */ }
|
Difference between signal and sigaction:
SignalEach time the function sets a specific signal processing function (non-sig_ign) to take effect only once, each time the process responds to the processing signal, the signal processing function is restored to the default processing method. therefore, if you want to process a signal in the same way multiple times, the usual practice is to call signal settings again at the beginning of the response function.
int sig_int();
//My signal handler
...
signal(SIGINT, sig_int);
...
int sig_int()
{
signal(SIGINT, sig_int);
....
}
One problem with this code segment is that, after a signal occurs, there is one between calling the S I g n a l function in the signal processing program.
Time Window. In this period, another interruption signal may occur. The second signal will cause the default action to be executed
The interrupt signal terminates the process. This type of program segments will work normally in most cases, making us think that they
True, but not true.
Another problem is that when a process does not want a signal to happen, it cannot close the signal.
Sigaction:
1. When the signal processing program is called, the new signal shielding words established by the system automatically include the signals being delivered. Therefore
If a given signal occurs again, it will be blocked until the processing of the previous signal ends.
2. The response function is always valid and will not be reset.
3. All signals except s I g a l r m attempt to set S A _ r e s ta RT sign, so these signals are interrupted
System Call (read, write) can be automatically restarted. The reason why you do not want to start the system call interrupted by the S I g a l r m signal is that you want to set a time limit for the I/O operation.
Therefore, if you want to use the same method to process multiple occurrences of a signal, you 'd better use sigaction. The signal only appears and is processed once. You can use signal