RST for network programming socket

Source: Internet
Author: User
Tags sendmsg connection reset htons

Three conditions for rst generation:

1. The destination is the SYN of a port, but there is no server being monitored on the port;

2. TCP wants to cancel an existing connection;

3. TCP receives a shard on a non-existent connection;


Now we can simulate the above three situations:

Client:

Struct sockaddr_in serveradd; bzero (& serveradd, sizeof (serveradd); serveradd. sin_family = af_inet; serveradd. sin_addr.s_addr = inet_addr (serv_addr); serveradd. sin_port = htons (serv_port); int connfd = socket (af_inet, sock_stream, 0); int connresult = connect (connfd, (struct sockaddr *) & serveradd, sizeof (serveradd )); if (connresult <0) {printf ("Connection Failed \ n"); close (connfd); return;} ssize_t writelen; char sendmsg [5000] = {0 }; unsigned long totalsize = 0; while (1) {writelen = write (connfd, sendmsg, sizeof (sendmsg); If (writelen <0) {printf ("failed to send errno = \ n", errno); return;} else {totalsize + = writelen; printf ("sent successfully totalsize = % ZD \ n ", totalsize );}}


Server:

# Define serv_port 8000int main (INT argc, const char * argv []) {struct sockaddr_in serveradd; struct sockaddr_in clientadd; bzero (& serveradd, sizeof (serveradd); serveradd. sin_family = af_inet; serveradd. sin_addr.s_addr = htonl (inaddr_any); serveradd. sin_port = htons (serv_port); socklen_t clientaddrlen; int listenfd = socket (af_inet, sock_stream, 0); int Yes = 1; setsockopt (listenfd, sol_socket, so_reuseaddr, (void *) & yes, sizeof (yes); If (listenfd <0) {printf ("failed to create socket \ n"); Return-1;} int bindresult = BIND (listenfd, (struct sockaddr *) & serveradd, sizeof (serveradd); If (bindresult <0) {printf ("failed to bind port \ n"); close (listenfd ); return-1;} Listen (listenfd, 20); int connfd; unsigned char recvmsg [246988]; unsigned long totalsize = 0; clientaddrlen = sizeof (clientadd ); connfd = accept (listenfd, (struct sockaddr *) & clientadd, & clientaddrlen); If (connfd <0) {printf ("Connection Failed \ n"); Return-1 ;} else {// here we are used for testing and only receive one connection close (listenfd);} Close (connfd); Return 0 ;}

Scenario 1:

Run the client program directly without running the server:

Client Print Information:

Connection Failed


Use a packet capture tool to capture packets:



The client initiates a three-way handshake through the connect method. After sending the first SYN Shard, the client receives the RST shard from the server;


Scenario 2:

Run the server and then the client program:

Client Print Information:

Sent successfullyTop talsize = 5000

Sent successfullyTop talsize = 10000

Sent successfullyTop talsize = 15000

......

Sent successfullyTop talsize = 125000

Sent successfullyTop talsize = 130000

(Lldb)


We can see that when the client sends the 130001-135000 bytes, the program crashes in the write method because the size of the TCP socket sending buffer is 131768 bytes, the sending buffer is not full when the first 130000 bytes are sent. Therefore, the write method returns success and continues sending.


Use a packet capture tool to capture packets:



If the server and client have established a connection, the server calls close and sends the fin segment to the client. In this case, the server cannot send or receive data through socket. In this case, the client calls read, if the received fin segment is 0, but the client can still write it to the server at this time, the write call is only responsible for handing the data to the TCP sending buffer to successfully return the result, so there is no error, when the server receives the data, it responds to an rst segment, indicating that the server cannot receive the data and the connection is reset. After the client receives the RST segment, it cannot immediately notify the application layer. It only saves the status on the TCP protocol layer. If the client calls write again to send data to the server, the TCP protocol layer is already in the RST state, so the data is not sent, but a sigpipe signal is sent to the application layer, the default processing action of the sigpipe signal is to terminate the program.


When a process performs a write operation on a socket that has received the rstEpipeError) the kernel sendsSigpipeSignal, the default action of this signal is to terminate the process, so the process must capture it so as not to be reluctantly terminated;


Continue to modify the client program as follows, and the server will not change:

Struct sockaddr_in serveradd; bzero (& serveradd, sizeof (serveradd); serveradd. sin_family = af_inet; serveradd. sin_addr.s_addr = inet_addr (serv_addr); serveradd. sin_port = htons (serv_port); int connfd = socket (af_inet, sock_stream, 0); int connresult = connect (connfd, (struct sockaddr *) & serveradd, sizeof (serveradd )); if (connresult <0) {printf ("Connection Failed \ n"); close (connfd); return;} ssize_t writelen; ssize_t readlen; char recvmsg [65535]; char sendmsg [5000] = {0}; unsigned long totalsize = 0; while (1) {writelen = write (connfd, sendmsg, sizeof (sendmsg )); if (writelen <0) {printf ("failed to send errno = % d \ n", errno); return;} else {totalsize + = writelen; printf ("sent successfully totalsize = % ZD \ n", totalsize);} Sleep (1); readlen = read (connfd, recvmsg, sizeof (recvmsg )); if (readlen <0) {printf ("failed to read errno = % d \ n", errno); return;} else {printf ("readlen: % LD \ n ", readlen );}}

After the client writes 5000 bytes to the server, it first sleeps for one second to send the data out, confirming that the TCP protocol layer has received the RST segment of the server response, and then performs the read operation, in this case, read returns-1. instead of 0;

Run the server first and then the client. The client prints the following information:

Sent successfullyTop talsize = 5000

Reading failedErrno = 54


# Defineeconnreset54/* Connection reset by peer */


When a process sendsRST(In this case, the read operation returnsEconnresetError)


The packet capture information is as follows:



The above situation will cause a problem: the server host process is terminated or restarted after a crash, and the client will not know if it does not write, and read will returnEconnresetError or timeout;

Solution: select:

1. If the peer TCP sends a fin (the peer process is terminated), the socket becomes readable and the read returns 0;

2. If the peer TCP sends an RST (the peer host crashes and restarts), the socket becomes readable and read returns-1, while errno contains the exact error code;

This issue is detailed in the SELECT statement.


Case 3:

Modify the client program as follows, and the server remains unchanged;

Run the server, and then run the client program. The client prints that the connection is successful. The if statement starts to sleep for 20 seconds. (In the server program, after receiving a connection, close the socket and immediately exit the program) during this period, open the server again, wait for the client to read the data to arrive at the shard, and then return an rst Shard to the client, because TCP receives a shard on a non-existent connection; restart the server host upon crash: TCP loses all connection information before the crash. Therefore, server TCP returns an rst for all received data from the customer;


Struct sockaddr_in serveradd; bzero (& serveradd, sizeof (serveradd); serveradd. sin_family = af_inet; serveradd. sin_addr.s_addr = inet_addr (serv_addr); serveradd. sin_port = htons (serv_port); int connfd = socket (af_inet, sock_stream, 0); int connresult = connect (connfd, (struct sockaddr *) & serveradd, sizeof (serveradd )); if (connresult <0) {printf ("Connection Failed \ n"); close (connfd); Return ;}else {printf ("connection successful \ n ");} ssize_t writelen; char sendmsg [5000] = {0}; unsigned long totalsize = 0; if (1) {sleep (20); writelen = write (connfd, sendmsg, sizeof (sendmsg); If (writelen <0) {printf ("failed to send errno = % d \ n", errno); return;} else {totalsize + = writelen; printf ("sent successfully totalsize = % ZD \ n", totalsize );}}


The packet capture information is as follows:




Refer:

UNIX Network programmingvolume 1, third edition: thesockets networking API


RST for network programming socket

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.