TIME_WAIT状态套接字重新使用

《TIME_WAIT相关知识》里边有相关理论知识。
《TIME_WAIT状态TCP连接导致套接字无法重用实验》有相关实验。

现代Linux的TCP协议栈已经做了许多升级,所以可以让我们直接重用TIME_WAIT状态套接字而不会引起问题。下边是优化的内容:

1.新连接的SYN告知序列号比原来TIME_WAIT老连接末序列号要大,所以就可以通过序列号分辨出来新老连接。
2.开启tcp_timestamps,这样就让新连接时间戳比旧连接时间戳大,这样可以通过检查时间戳来判断新老连接。

在这样两重优化下,重用TIME_WAIT状态连接就不会产生任何问题了。

int on = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

SO_REUSEADDR用来告诉操作系统内核,如果端口已被占用,但是 TCP 连接状态位于 TIME_WAIT ,可以重用端口。这段代码需要放到socket函数和bind函数之间。
下边是timeWaitSetsockopt.c完整代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include

void error_handling(char *buf);

#define  MAXLINE     1024
static int count;
static void sig_int(int signo) {
    printf("\nreceived %d datagrams\n", count);
    exit(0);
}
int main(int argc, char **argv) {
    if (argc != 2) {
        error_handling("usage: select01  or ");
    }



    int serv_sock = socket(AF_INET,SOCK_STREAM,0);

    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family=AF_INET;
    server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
    server_addr.sin_port=htons(atoi(argv[1]));
    // SO_REUSEADDR用来告诉操作系统内核,如果端口已被占用,但是 TCP 连接状态位于 TIME_WAIT ,可以重用端口
    int on = 1;
    setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

    if(bind(serv_sock, (struct sockaddr*) &server_addr, sizeof(server_addr))==-1){
        fprintf(stderr, "error in bind: %s (%d)\n", strerror(errno), errno);
                    exit(errno);
    }
        if(listen(serv_sock, 5)==-1){
        fprintf(stderr, "error in listen: %s (%d)\n", strerror(errno), errno);
                    exit(errno);
    }


    signal(SIGPIPE, sig_int);


     int connfd;
    struct sockaddr_in client_addr;
    socklen_t client_len = sizeof(client_addr);

    if ((connfd = accept(serv_sock, (struct sockaddr *) &client_addr, &client_len)) < 0) {
        printf("accept failed");
        exit(0);
    }

    char message[MAXLINE];
    count = 0;
    int n;
    for (;;) {
        int n = read(connfd, message, MAXLINE);
        if (n < 0) {
            fprintf(stderr, "error in read: %s (%d)\n", strerror(errno), errno);
                    exit(0);
        } else if (n == 0) {
            fprintf(stderr, "client closed: %s (%d)\n", strerror(0), 0);
            exit(0);
        }
        message[n] = 0;
        printf("received %d bytes: %s\n", n, message);
        count++;
    }
}
void error_handling(char *buf)
{
        fputs(buf, stderr);
        fputc('\n', stderr);
        exit(1);
}

在服务器端sudo gcc timeWaitSetsockopt.c -o timeWaitSetsockopt进行编译,sudo ./timeWaitSetsockopt 8080启动程序。
TIME_WAIT状态套接字重新使用_第1张图片

在客户端使用sudo telnet 127.0.0.1 8080进行连接,然后输入good之后按下回车键。
TIME_WAIT状态套接字重新使用_第2张图片

然后在服务器端同时按住ctrl+c关闭程序,之后快速再使用sudo ./timeWaitSetsockopt 8080启动程序,然后快速在客户端使用sudo telnet 127.0.0.1 8080进行连接,输入network之后按下回车键,还是需要在服务器端快速按下sudo netstat -altnp | grep 8080看一下连接状态,这些动作只要够快就可以出现两条记录。
TIME_WAIT状态套接字重新使用_第3张图片

你可能感兴趣的:(网络编程实战,tcp)