• 套接字半关闭与关闭


    套接字半关闭与关闭 (可参考TCP/IP网络编程)
    套接字的半关闭状态: 可以传输但不可接收或可接收但不可传输,即只关闭流的一半.
    shutdown()函数的三种断开连接方式:
        SHUT_RD:    断开输入流  
        SHUT_WR:    断开输出流
        SHUT_RDWR:  同时断开I/O区别:
        如果传入SHUT_RD 那么无法接收数据,即使数据到缓冲区了也会抹去并无法调用相关读取函数.
        如果传入SHUT_WR 那么无法输出数据了, 但如果输出缓冲中还有未传输的数据会首先传输完毕. [这是与SHUT_RD的区别]. close()才不管缓冲区还有没有内容直接全抹掉.
    
    打算关闭套接字连接时close()shutdown()都会向客户端发送EOF符号表示传输结束.
    而调用close()函数会同时关闭I/O流,并且再也无法接收对方的数据了. 使用shutdown()进行半关闭就比较优雅了, 我可以发送完EOF后等待客户端发送的最后一次数据(SHUT_WD).
       比如下面的服务端代码:
       
        while (1) {
            read_cnt = fread((void*)buf, 1, BUF_SIZE,fp);
            if(read_cnt < BUF_SIZE) {
               break;       //我输出完毕之后推出循环
            }
        }
        shutdown(client_fd,SHUT_WR);            //告诉客户端我不再发数据给你了
        read(client_fd, buf, BUF_SIZE);         //阻塞在这等客户端最后一次发数据过来.
        printf("msg from client:%s
    ", buf);    //打印客户端最后一次数据
        fclose(fp);
        close(client_fd);                       //正式关闭客户端套接字
        close(server_fd);
     
     
     closesocketshutdown(使用SHUT_WR当作参数时),会向通信对方发出一个fin包,
     而此时套接字的状态会由ESTABLISHED变成FIN_WAIT_1,然后对方发送一个ACK包作为回应,
     套接字又变成FIN_WAIT_2,如果对方也关闭了连接则对方会发出FIN我方会回应一个ACK并将套接字置为TIME_WAIT。因此可以看出closesocket,shutdown所进行的TCP行为是一样的,
     所不同的是函数部分,shutdown会确保windows建立的数据传输队列中的数据不被丢失,
     而closesocket会冒然的抛弃所有的数据,因此如果你愿意closesocket完全可以取代shutdown,
     然而在数据交互十分复杂的网络协议程序中,最好还是shutdown稳妥一些!   
        
    
     @1. (ESTABLISHED) -- shutdown -> 服务端(FIN_WAIT_1) --fin-> 客户端 --ack-> 服务端(FIN_WAIT_2)
        @2. 客户端 --fin--> 服务端 --ack--> 客户端(TIME_WAIT);
            @3. 客户端套接字处于TIME_WAIT 阶段即处于等待回收状态,
    
    windows默认4分钟后自动回收, 既然是资源那有稀缺性, 
    比如nginx默认可操作1024个文件描述符(套接字), 如果这些TIME_WAIT待回收的或CLOSE_WAIT(调用close()产生待回收)的套接字占用太多而无法及时回收的话,
    那么nginx剩下可用于建立ESTABLISHED的套接字资源就不足了, 那么就无法继续接受请求,
    于是报"Too Many Open Files异常"或卡主(nginx还必须维护这些TIME_WAIT套接字), 
    再比如mysql配置max-connections=2048, 一旦没有可用的连接(套接字),mysql就会报too many connections, 因此及时的回收或重新利用这些TIME_WAIT 就显得很关键了. 
    
    HTTP协议1.1版规定default行为是Keep-Alive,也就是会重用TCP连接(套接字)传输多个 request/response,一个主要原因就是发现了这个问题. 即告诉套接字别发完一个就像等待被回收了, 继续站岗循环使用吧.
    
    继续看下面的案例怎么通过修改内核配置尽快回收套接字.        
    vim /etc/sysctl.conf
    
    编辑文件,加入以下内容:
    net.ipv4.tcp_syncookies = 1
    net.ipv4.tcp_tw_reuse = 1
    net.ipv4.tcp_tw_recycle = 1
    net.ipv4.tcp_fin_timeout = 30
    然后执行 /sbin/sysctl -p 让参数生效。
    
    
    net.ipv4.tcp_syncookies = 1  表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
    net.ipv4.tcp_tw_reuse = 1    表示开启重用。允许将time-wait sockets重新用于新的TCP连接,默认为0,表示关闭;
    net.ipv4.tcp_tw_recycle = 1  表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
    net.ipv4.tcp_fin_timeout    修改系統默认的 TIMEOUT 时间

     

  • 相关阅读:
    ElasticSearch学习记录
    用java代码手动控制kafkaconsumer偏移量
    kafka0.9.0及0.10.0配置属性
    kafka常用命令
    kafka消费者客户端(0.9.0.1API)
    kafka入门教程链接
    编程内功
    bzoj3145:[Feyat cup 1.5]Str
    3 SpringBoot与微服务
    2 微服务存在的问题和解决方案
  • 原文地址:https://www.cnblogs.com/zyp221314/p/9228701.html
Copyright © 2020-2023  润新知