• 优雅关闭TCP的函数shutdown效果展示


    《TCP关闭的两种方法概述》里边理论基础,下边是列出代码,并且进行实验。
    服务端代码graceserver.c的内容如下:

    #include "lib/common.h"
    
    static int count;
    
    static void sig_int(int signo) {
        printf("\nreceived %d datagrams\n", count);
        exit(0);
    }
    
    int main(int argc, char **argv) {
        int listenfd;
        listenfd = socket(AF_INET, SOCK_STREAM, 0);
    
        struct sockaddr_in server_addr;
        bzero(&server_addr, sizeof(server_addr));
        server_addr.sin_family = AF_INET;
        server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
        server_addr.sin_port = htons(SERV_PORT);
    
        int rt1 = bind(listenfd, (struct sockaddr *) &server_addr, sizeof(server_addr));
        if (rt1 < 0) {
            error(1, errno, "bind failed ");
        }
    
        int rt2 = listen(listenfd, LISTENQ);
        if (rt2 < 0) {
            error(1, errno, "listen failed ");
        }
    
        signal(SIGINT, sig_int);
        signal(SIGPIPE, SIG_IGN);
    
        int connfd;
        struct sockaddr_in client_addr;
        socklen_t client_len = sizeof(client_addr);
    
        if ((connfd = accept(listenfd, (struct sockaddr *) &client_addr, &client_len)) < 0) {
            error(1, errno, "bind failed ");
        }
    
        char message[MAXLINE];
        count = 0;
    
        for (;;) {
            int n = read(connfd, message, MAXLINE);
            if (n < 0) {
                error(1, errno, "error read");
            } else if (n == 0) {
                error(1, 0, "client closed \n");
            }
            message[n] = 0;
            printf("received %d bytes: %s\n", n, message);
            count++;
    
            char send_line[MAXLINE];
            sprintf(send_line, "Hi, %s", message);
    
            sleep(5);
    
            int write_nc = send(connfd, send_line, strlen(send_line), 0);
            printf("send bytes: %zu \n", write_nc);
            if (write_nc < 0) {
                error(1, errno, "error write");
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    客户端代码graceclient.c内容如下:

    # include "lib/common.h"
    # define    MAXLINE     4096
    
    int main(int argc, char **argv) {
        if (argc != 2) {
            error(1, 0, "usage: graceclient ");
        }
        
        int socket_fd;
        socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    
        struct sockaddr_in server_addr;
        bzero(&server_addr, sizeof(server_addr));
        server_addr.sin_family = AF_INET;
        server_addr.sin_port = htons(SERV_PORT);
        inet_pton(AF_INET, argv[1], &server_addr.sin_addr);
    
        socklen_t server_len = sizeof(server_addr);
        int connect_rt = connect(socket_fd, (struct sockaddr *) &server_addr, server_len);
        if (connect_rt < 0) {
            error(1, errno, "connect failed ");
        }
    
        char send_line[MAXLINE], recv_line[MAXLINE + 1];
        int n;
    
        fd_set readmask;
        fd_set allreads;
    
        FD_ZERO(&allreads);
        FD_SET(0, &allreads);
        FD_SET(socket_fd, &allreads);
        for (;;) {
            readmask = allreads;
            int rc = select(socket_fd + 1, &readmask, NULL, NULL, NULL);
            if (rc <= 0)
                error(1, errno, "select failed");
            if (FD_ISSET(socket_fd, &readmask)) {
                n = read(socket_fd, recv_line, MAXLINE);
                if (n < 0) {
                    error(1, errno, "read error");
                } else if (n == 0) {
                    error(1, 0, "server terminated \n");
                }
                recv_line[n] = 0;
                fputs(recv_line, stdout);
                fputs("\n", stdout);
            }
            if (FD_ISSET(0, &readmask)) {
                if (fgets(send_line, MAXLINE, stdin) != NULL) {
                    if (strncmp(send_line, "shutdown", 8) == 0) {
                        FD_CLR(0, &allreads);
                        if (shutdown(socket_fd, 1)) {
                            error(1, errno, "shutdown failed");
                        }
                    } else if (strncmp(send_line, "close", 5) == 0) {
                        FD_CLR(0, &allreads);
                        if (close(socket_fd)) {
                            error(1, errno, "close failed");
                        }
                        sleep(6);
                        exit(0);
                    } else {
                        int i = strlen(send_line);
                        if (send_line[i - 1] == '\n') {
                            send_line[i - 1] = 0;
                        }
    
                        printf("now sending %s\n", send_line);
                        size_t rt = write(socket_fd, send_line, strlen(send_line));
                        if (rt < 0) {
                            error(1, errno, "write failed ");
                        }
                        printf("send bytes: %zu \n", rt);
                    }
    
                }
            }
    
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

    代码如上,想要跟我一样编译以后进行测试的话,需要先参考《网络编程实战课程使用Cmake第一次编译程序》进行编译,之后再来验证套接字上的closeshutdown两个函数。

    实验一

    在其中一个终端,输入./graceserver然后按下一个回车,打开服务器程序。
    之后再打开一个终端,输入./graceclient 127.0.0.1然后按下一个回车,打开客户端程序,然后先验证套接字的close函数,快速在5秒内输出data1data2close三个字符串。
    在这里插入图片描述
    可以看到close函数直接就把客户端套接字的读写两个方向都关闭了。

    实验二

    在其中一个终端,输入./graceserver然后按下一个回车,打开服务器程序。
    之后再打开一个终端,输入./graceclient 127.0.0.1然后按下一个回车,打开客户端程序,然后先验证套接字的close函数,快速在5秒内输出data1data2shutdown三个字符串。
    在这里插入图片描述
    这里可以看到shutdown只是先把客户端写方向关闭,但是读的方向还打开着,这就是为什么还能接受到服务器端的Hi, data1Hi, data2两个字符串。

    此文章为11月Day 11学习笔记,内容来源于极客时间《网络编程实战》

  • 相关阅读:
    数字图像处理笔记(二)图像增强-直方图修改技术
    MySQL InnoDB 引擎底层解析(二)
    APP攻防--安卓逆向&JEB动态调试&LSPosed模块&算法提取&Hook技术
    推荐一款强大的开源自动化测试神器
    精准DNA甲基化/羟甲基化测序(oxBS-seq)|易基因技术推介
    vue项目部署和镜像打包
    苹果推送和开发证书更新
    【RabbitMQ 实战】12 镜像队列
    学习之浅谈python如何做接口自动化
    FPGA 学习笔记:Vivado 配置IO引脚约束
  • 原文地址:https://blog.csdn.net/qq_42108074/article/details/134340752