zoukankan      html  css  js  c++  java
  • Linux下高性能网络编程中的几个TCP/IP选项

    Linux下高性能网络编程中的几个TCP/IP选项,关于Linux下高性能网络编程中的几个TCP/IP选项的文章-Linux-尚观知识库

    Linux下高性能网络编程中的几个TCP/IP选项

    本文地址: http://www.uplook.cn/blog/8/81276/

    [ 本文作者:njdragonfly ]

    Linux下高性能网络编程中的几个TCP/IP选项,

    转载自: http://blog.chinaunix.net/u/12592/showart.php?id=2064847

    最近在新的平台上测试程序,以前一些没有注意到的问题都成为了性能瓶颈,通过设置一些TCP/IP选项能够解决一部分问题,当然根本的解决方法是重构代码,重新设计服务器框架。先列出几个TCP/IP选项:

    选项
    man 7 socket:
    SO_REUSEADDR
    SO_RECVBUF/SO_SNDBUF
    SO_KEEPALIVE
    SO_LINGER

    man 7 tcp:
    TCP_CORK
    TCP_NODELAY
    TCP_DEFER_ACCEPT
    TCP_KEEPCNT/TCP_KEEPIDLE/TCP_KEEPINTVL

    SO_REUSEADDR
    在服务器程序中,SO_REUSEADDR socket选项通常在调用bind()之前被设置。
    SO_REUSEADDR可以用在以下四种情况下。 
    (摘自《Unix网络编程》卷一,即UNPv1)
    1、当有一个有相同本地地址和端口的socket1处于TIME_WAIT状态时,而你启动的程序的socket2要占用该地址和端口,你的程序就要用到该选项。 
    2、SO_REUSEADDR允许同一port上启动同一服务器的多个实例(多个进程)。但每个实例绑定的IP地址是不能相同的。在有多块网卡或用IP Alias技术的机器可以测试这种情况。 
    3、SO_REUSEADDR允许单个进程绑定相同的端口到多个socket上,但每个socket绑定的ip地址不同。这和2很相似,区别请看UNPv1。 
    4、SO_REUSEADDR允许完全相同的地址和端口的重复绑定。但这只用于UDP的多播,不用于TCP。

    TCP_NODELAY/TCP_CHORK
    TCP_NODELAY和TCP_CORK基本上控制了包的“Nagle化”,Nagle化在这里的含义是采用Nagle算法把较小的包组装为更大的帧。TCP_NODELAY和TCP_CORK都禁掉了Nagle算法,只不过他们的行为不同而已。
    TCP_NODELAY 不使用Nagle算法,不会将小包进行拼接成大包再进行发送,直接将小包发送出去,会使得小包时候用户体验非常好。
    当在传送大量数据的时候,为了提高TCP发送效率,可以设置TCP_CORK,CORK顾名思义,就是"塞子"的意思,它会尽量在每次发送最大的数据量。当设置了TCP_CORK后,会有阻塞200ms,当阻塞时间过后,数据就会自动传送。

    详细的资料可以查看参考文献5。

    SO_LINGER
    linger,顾名思义是延迟延缓的意思,这里是延缓面向连接的socket的close操作。默认,close立即返回,但是当发送缓冲区中还有一部分数据的时候,系统将会尝试将数据发送给对端。SO_LINGER可以改变close的行为。控制SO_LINGER通过下面一个结构:
    struct linger
    {
     int l_onoff; /*0=off, nonzero=on*/
     int l_linger; /*linger time, POSIX specifies units as seconds*/
    };

    通过结构体中成员的不同赋值,可以表现为下面几种情况:
    1. l_onoff设置为0,选项被关闭。l_linger值被忽略,就是上面的默认情形,close立即返回。
    2. l_onoff设置为非0,l_linger被设置为0,则close()不被阻塞立即执行,丢弃socket发送缓冲区中的数据,并向对端发送一个RST报文。这种关闭方式称为“强制”或“失效”关闭。
    3. l_onoff设置为非0,l_linger被设置为非0,则close()调用阻塞进程,直到所剩数据发送完毕或超时。这种关闭称为“优雅的”关闭。

    注意:
    这个选项需要谨慎使用,尤其是强制式关闭,会丢失服务器发给客户端的最后一部分数据。UNP中:
    The TIME_WAIT state is our friend and is there to help us(i.e., to let the old duplicate segments expire in the network).

    TCP_DEFER_ACCEPT
    defer accept,从字面上理解是推迟accept,实际上是当接收到第一个数据之后,才会创建连接。对于像HTTP等非交互式的服务器,这个很有意义,可以用来防御空连接攻击(只是建立连接,但是不发送任何数据)。
    使用方法如下:

    val = 5;
    setsockopt(srv_socket->fd, SOL_TCP, TCP_DEFER_ACCEPT, &val, sizeof(val)) ;

    里面 val 的单位是秒,注意如果打开这个功能,kernel 在 val 秒之内还没有收到数据,不会继续唤醒进程,而是直接丢弃连接。如果服务器设置TCP_DEFER_ACCEPT选项后,服务器受到一个CONNECT请求后,三次握手之后,新的socket状态依然为SYN_RECV,而不是ESTABLISHED,操作系统不会Accept。
    由于设置TCP_DEFER_ACCEPT选项之后,三次握手后状态没有达到ESTABLISHED,而是SYN_RECV。这个时候,如果客户端一直没有发送"数据"报文,服务器将重传SYN/ACK报文,重传次数受net.ipv4.tcp_synack_retries参数控制,达到重传次数之后,才会再次进行setsockopt中设置的超时值,因此会出现SYN_RECV生存时间比设置值大一些的情况。

    关于SYN_RECV状态可以查看参考文献7。

    SO_KEEPALIVE/TCP_KEEPCNT/TCP_KEEPIDLE/TCP_KEEPINTVL
    如果一方已经关闭或异常终止连接,而另一方却不知道,我们将这样的TCP连接称为半打开的。TCP通过保活定时器(KeepAlive)来检测半打开连接。
    在高并发的网络服务器中,经常会出现漏掉socket的情况,对应的结果有一种情况就是出现大量的CLOSE_WAIT状态的连接。这个时候,可以通过设置KEEPALIVE选项来解决这个问题,当然还有其他的方法可以解决这个问题,详细的情况可以查看参考资料8。

    使用方法如下:

    //Setting For KeepAlive
    int keepalive = 1;
    setsockopt(incomingsock,SOL_SOCKET,SO_KEEPALIVE,(void*)(&keepalive),(socklen_t)sizeof(keepalive));
                            
    int keepalive_time = 30;
    setsockopt(incomingsock, IPPROTO_TCP, TCP_KEEPIDLE,(void*)(&keepalive_time),(socklen_t)sizeof(keepalive_time));
    int keepalive_intvl = 3;
    setsockopt(incomingsock, IPPROTO_TCP, TCP_KEEPINTVL,(void*)(&keepalive_intvl),(socklen_t)sizeof(keepalive_intvl));
    int keepalive_probes= 3;
    setsockopt(incomingsock, IPPROTO_TCP, TCP_KEEPCNT,(void*)(&keepalive_probes),(socklen_t)sizeof(keepalive_probes));


    设置SO_KEEPALIVE选项来开启KEEPALIVE,然后通过TCP_KEEPIDLE、TCP_KEEPINTVL和TCP_KEEPCNT设置keepalive的开始时间、间隔、次数等参数。
    当然,也可以通过设置/proc/sys/net/ipv4/tcp_keepalive_time、tcp_keepalive_intvl和tcp_keepalive_probes等内核参数来达到目的,但是这样的话,会影响所有的socket,因此建议使用setsockopt设置。

    参考:
    1. man 7 socket
    2. man 7 tcp
    3. 《Unix Network Programming》 Section 7.5 "Generic Socket Options"
    4. http://www.linuxsir.org/bbs/showthread.php?t=55738
    5. http://blog.chinaunix.net/u/12592/showart_1723934.html
    6. http://blog.csdn.net/fullsail/archive/2009/08/09/4429102.aspx
    7. http://www.kernelchina.org/?q=node/110
    8. http://blog.chinaunix.net/u/12592/showart.php?id=2059174

    来自CSDN网站njdragonfly博客

  • 相关阅读:
    Python queue 模块详解
    贪婪算法的解题思路
    python中os.path.abspath和os.path.realpath区别
    python报错UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 4: ordinal not in range
    Python Socket Error: Address already in use的解决办法
    Python里的string 和 unicode 区别讲得很明白的文章
    linux环境,crontab报错Authentication token is no longer valid; new one required You (aimonitor) are not allowed to access to (crontab) because of pam configuration.
    Mac系统使用Parallels Desktop安装Win10
    windows update国内服务器
    黄海机器的向日葵远程帐号
  • 原文地址:https://www.cnblogs.com/lexus/p/2983712.html
Copyright © 2011-2022 走看看