c++ - linux下accept之前异常终止连接问题?
巴扎黑
巴扎黑 2017-04-17 15:34:59
0
2
775

服务端代码:


#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdint.h>
#include <assert.h>
#include <fcntl.h>
#include <string.h>
#include <bits/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>

const char* ip = "192.168.16.105";
uint16_t port = 8888;
char buff[1024];

void make_sock_noblocking(int sock_fd)
{
    int flags = fcntl(sock_fd, F_GETFL, 0);
    flags |= O_NONBLOCK;
    fcntl(sock_fd, F_SETFL, flags);
}

int main()
{
    int listen_fd = socket(PF_INET, SOCK_STREAM, 0);

    struct sockaddr_in sock_addr;
    memset(&sock_addr, 0, sizeof(sock_addr));
    sock_addr.sin_family = AF_INET;
    sock_addr.sin_port = htons(port);
    inet_pton(AF_INET, ip, &(sock_addr.sin_addr));

    int optval = 1;
    setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR,
               (const void *)&optval , sizeof(int));
    int ret = bind(listen_fd, (sockaddr*)&sock_addr, sizeof(sock_addr));

    listen(listen_fd, 1024);

    make_sock_noblocking(listen_fd);

    sleep(10);

    struct sockaddr_in client_addr;
    memset(&sock_addr, 0, sizeof(client_addr));
    socklen_t len = sizeof(client_addr);
    int conn_fd = accept(listen_fd, (sockaddr*)&client_addr, &(len));

    printf("%d--------%s\n", conn_fd, strerror(errno));

    int read_bytes = read(conn_fd, buff, sizeof(buff));

    printf("%d %s\n", read_bytes, strerror(errno));

    return 0;
}

客户端代码:


#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdint.h>
#include <assert.h>
#include <fcntl.h>
#include <string.h>
#include <bits/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>

const char* ip = "192.168.16.105";
uint16_t port = 8888;

int main()
{
    int sock_fd = socket(PF_INET, SOCK_STREAM, 0);

    struct sockaddr_in sock_addr;
    memset(&sock_addr, 0, sizeof(sock_addr));
    sock_addr.sin_family = AF_INET;
    sock_addr.sin_port = htons(port);
    inet_pton(AF_INET, ip, &(sock_addr.sin_addr));

    int ret = connect(sock_fd, (sockaddr*)&sock_addr, sizeof(sock_addr));

    if(ret < 0)
    {
        printf("%s\n", strerror(errno));
    }

    struct linger my_linger;
    memset(&my_linger, 0, sizeof(my_linger));
    my_linger.l_onoff = 1;
    my_linger.l_linger = 0;

    setsockopt(sock_fd, SOL_SOCKET, SO_LINGER, &my_linger, sizeof(my_linger));

    close(sock_fd);

    return 0;
}

问题:
accpet之前sleep 10秒钟,这期间客户端向服务端发送RST终止连接,但是服务端这边还是会成功接受连接。按unp讲的不应该是返回一个ECONNABORTED(POSIX.1)错误吗?如果我把套接字的非阻塞去掉变成阻塞的话,依然可以成功接受连接,accept并不会阻塞,但是accept取出的这个socket去读的话就会出现Connection reset by peer错误了。莫非linux的实现是不管accept之前是不是被RST了,只管取出来,但取出来的这个socket再操作的话就会报错?

巴扎黑
巴扎黑

reply all(2)
阿神

After listening, the system will maintain the corresponding queue and process all connections to this listening socket. Accept will remove the completed connection from the queue. Therefore, regardless of whether you call accept or not, the TCP connection from the client can complete the three-way handshake.
According to your code, first the server starts listening, and then enters sleep. During this period, the client is run, and first calls connect to complete the three-way handshake. At this time, the server establishes a completed connection and puts it in the queue. The client then calls close closes the connection and sends FIN. I believe it should have received ACK. Because TCP is a full-duplex protocol, the server needs to close a connection by itself. The client just closes its own connection, and the server's connection still exists. So you can accept the connection, but subsequent operations on the socket will return an error and need to be actively closed.
I didn’t notice that RST was used to terminate the connection before. I looked at the kernel code of 2.6.32. After receiving the RST, the server will clean up all the status and directly disconnect the connection, but the requested resources will not be recycled. This The process is completed in close. Therefore, when accepting, the structure in the listening queue still exists and can be taken out. Accept itself is indeed just a retrieval process.

洪涛

Regardless of sleep10 or not, the client is blocked in connect. When the server comes to read the socket, the client has been closed, and then an error connection reset by peer is reported

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template