SO_LINGER RST linger

如果我们在调用accept函数返回之前, 该客户端TCP发送了一个RST(复位)。在服务器中, 表现为该连接仍在TCP队列中, 等待服务器进程调用accept的时候RST到达。此时返回的套接字是一个已连接,但是却有接受了RST的套接字。

模型图如下:

 

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <arpa/inet.h>

#define SERV_PORT 10001
#define SERV_IP "0.0.0.0"

int main(void) {
    int sfd, cfd;
    int len, i;
    //BUFSIZ是系统内嵌的一个宏,用来指定buf大小
    char buf[BUFSIZ], clie_IP[BUFSIZ];
    struct sockaddr_in serv_addr, clie_addr;
    socklen_t clie_addr_len;
    sfd = socket(AF_INET, SOCK_STREAM, 0);
    bzero(&serv_addr, sizeof(serv_addr));      
    serv_addr.sin_family = AF_INET;           
    inet_pton(AF_INET , SERV_IP , &serv_addr.sin_addr.s_addr);
    serv_addr.sin_port = htons(SERV_PORT);              

    //绑定套接字
    bind(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
    listen(sfd, 64);
    printf("wait for client connect ...
");
    clie_addr_len = sizeof(clie_addr);
    while(1)
    {   
        //在accept之前休眠10s
        sleep(10);

        //阻塞等待客户端发起连接
        cfd = accept(sfd, (struct sockaddr *)&clie_addr, &clie_addr_len);
        //打印accept后的信息和客户端的连接
        if(cfd > 0) {
            printf("accept cfd = %d
" , cfd);
        }

        printf("client IP:%s	port:%d
", 
            inet_ntop(AF_INET, &clie_addr.sin_addr.s_addr, clie_IP, sizeof(clie_IP)), 
            ntohs(clie_addr.sin_port));

        //服务端读取数据
        len = read(cfd, buf, sizeof(buf));
        //read返回0说明对端已经关闭
        if(len < 0) {
            //进一步判断是否收到RST
            if(errno == ECONNRESET) {
                printf("read reset by peer
");
                break;
            }
        }
    }
    close(sfd);
    close(cfd);
    return 0;
}
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>

#define SERV_IP "127.0.0.1"
#define SERV_PORT 10001

int main(void) {
    int sfd, len,ret;
    struct sockaddr_in serv_addr;
    struct linger lgr;
    char buf[BUFSIZ];

    sfd = socket(AF_INET, SOCK_STREAM, 0);
    if(ret < 0){
        perror("set SO_LINGER Error");
    }

    bzero(&serv_addr, sizeof(serv_addr));                       
    serv_addr.sin_family = AF_INET;                         
    inet_pton(AF_INET, SERV_IP, &serv_addr.sin_addr.s_addr); 
    serv_addr.sin_port = htons(SERV_PORT);                      

    //客户端connect连接返回,通过SO_LINGER选项立刻发送RST
    lgr.l_onoff = 1;
    lgr.l_linger = 0;
    ret = setsockopt(sfd, SOL_SOCKET, SO_LINGER, &lgr, sizeof lgr);

    ret = connect(sfd, (struct sockaddr *)&serv_addr ,  sizeof(serv_addr));
    if(ret == 0)
    {
        printf("client connect successful
");
    }

    //关闭链接
    close(sfd);
    return 0;
}

 RST报文

demo2

服务端不变

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>

#define SERV_IP "127.0.0.1"
#define SERV_PORT 10001

int main(void) {
    int sfd, len,ret;
    struct sockaddr_in serv_addr;
    struct linger lgr;
    char buf[BUFSIZ];

    sfd = socket(AF_INET, SOCK_STREAM, 0);
    if(ret < 0){
        perror("set SO_LINGER Error");
    }

    bzero(&serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    inet_pton(AF_INET, SERV_IP, &serv_addr.sin_addr.s_addr);
    serv_addr.sin_port = htons(SERV_PORT);

    //客户端connect连接返回,通过SO_LINGER选项立刻发送RST
    lgr.l_onoff = 1;
    lgr.l_linger = 10; 
    ret = setsockopt(sfd, SOL_SOCKET, SO_LINGER, &lgr, sizeof lgr);

    ret = connect(sfd, (struct sockaddr *)&serv_addr ,  sizeof(serv_addr));
    if(ret == 0)
    {
        printf("client connect successful
");
    }

    //关闭链接
    close(sfd);
    return 0;
}

 

更改l_linger 

//客户端connect连接返回,通过SO_LINGER选项立刻发送RST
    lgr.l_onoff = 1;
    lgr.l_linger = 1;
    ret = setsockopt(sfd, SOL_SOCKET, SO_LINGER, &lgr, sizeof lgr);

demo3

//客户端connect连接返回,通过SO_LINGER选项立刻发送RST
    lgr.l_onoff = 0;
    lgr.l_linger = 1;
    ret = setsockopt(sfd, SOL_SOCKET, SO_LINGER, &lgr, sizeof lgr);

demo4

int main(void) {
    int sfd, len,ret;
    struct sockaddr_in serv_addr;
    struct linger lgr;
    char buf[BUFSIZ];

    sfd = socket(AF_INET, SOCK_STREAM, 0);
    if(ret < 0){
        perror("set SO_LINGER Error");
    }

    bzero(&serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    inet_pton(AF_INET, SERV_IP, &serv_addr.sin_addr.s_addr);
    serv_addr.sin_port = htons(SERV_PORT);

    //客户端connect连接返回,通过SO_LINGER选项立刻发送RST
    lgr.l_onoff = 1;
    lgr.l_linger = 10;
    ret = setsockopt(sfd, SOL_SOCKET, SO_LINGER, &lgr, sizeof lgr);

    ret = connect(sfd, (struct sockaddr *)&serv_addr ,  sizeof(serv_addr));
    if(ret == 0)
    {
        printf("client connect successful
");
    }

    //关闭链接
    close(sfd);
    write(sfd, "hello", sizeof("hello"));
    return 0;
}

TCP异常处理(accept返回前连接中止)与SO_LINGER选项

原文地址:https://www.cnblogs.com/dream397/p/14686217.html