Socket参数说明

SO_LINGER


   此选项指定函数close对面向连接的协议如何操作(如TCP)。缺省close操作是立即返回,如果有数据残留在套接口缓冲区中则系统将试着将这些数据发送给对方。

SO_LINGER选项用来改变此缺省设置。使用如下结构:

struct linger {
     int l_onoff; /* 0 = off, nozero = on */
     int l_linger; /* linger time */
};

有下列三种情况:

  • l_onoff为0,则该选项关闭,l_linger的值被忽略,等于缺省情况,close立即返回;
    l_onoff为非0,l_linger为0,则套接口关闭时TCP夭折连接,TCP将丢弃保留在套接口发送缓冲区中的任何数据并发送一个RST给对方,而不是通常的四分组终止序列,这避免了TIME_WAIT状态;

  • l_onoff 为非0,l_linger为非0,当套接口关闭时内核将拖延一段时间(由l_linger决定)。
    如果套接口缓冲区中仍残留数据,进程将处于睡眠状态,直 到(a)所有数据发送完且被对方确认,之后进行正常的终止序列(描述字访问计数为0)或(b)延迟时间到。
    此种情况下,应用程序检查close的返回值是非常重要的,如果在数据发送完并被确认前时间到,close将返回EWOULDBLOCK错误且套接口发送缓冲区中的任何数据都丢失。
    close的成功返回仅告诉我们发送的数据(和FIN)已由对方TCP确认,它并不能告诉我们对方应用进程是否已读了数据。如果套接口设为非阻塞的,它将不等待close完 成。

  • l_linger的单位依赖于实现,4.4BSD假设其单位是时钟滴答(百分之一秒),但Posix.1g规定单位为秒。

--------------------------------华丽的分割线---------------------------------------------------

TCP_NODELAY和TCP_CORK

    基本上控制了包的“Nagle化”,Nagle化在这里的含义是采用Nagle算法把较小的包组装为更大的帧。

    John Nagle是Nagle算法的发明人,后者就是用他的名字来命名的,他在1984年首次用这种方法来尝试解决福特汽车公司的网络拥塞问题(欲了解详情请参 看IETF RFC 896)。

    他解决的问题就是所谓的silly window syndrome ,中文称“愚蠢窗口症候群”,具体含义是:

    因为普遍终端应用程序每产生一次击键操作就会发送一个包,而典型情况下一个包会拥有一个字节的数据载荷以及40 个字节长的包头,于是产生4000%的过载,很轻易地就能令网络发生拥塞,。

    Nagle化后来成了一种标准并且立即在因特网上得以实现。它现在已经成为缺省配置了,但在我们看来,有些场合下把这一选项关掉也是合乎需要的。

    现在让我们假设某个应用程序发出了一个请求,希望发送小块数据。我们可以选择立即发送数据或者等待产生更多的数据然后再一次发送两种策略。

    如果我们马上发 送数据,那么交互性的以及客户/服务器型的应用程序将极大地受益。

    例如,当我们正在发送一个较短的请求并且等候较大的响应时,相关过载与传输的数据总量相 比就会比较低,而且,如果请求立即发出那么响应时间也会快一些。以上操作可以通过设置套接字的TCP_NODELAY选项来完成,这样就禁用了Nagle 算法。 另外一种情况则需要我们等到数据量达到最大时才通过网络一次发送全部数据,这种数据传输方式有益于大量数据的通信性能,典型的应用就是文件服务器。应用 Nagle算法在这种情况下就会产生问题。

    但是,如果你正在发送大量数据,你可以设置TCP_CORK选项禁用Nagle化,其方式正好同 TCP_NODELAY相反(TCP_CORK 和 TCP_NODELAY 是互相排斥的)。

    下面就让我们仔细分析下其工作原理。

    假设应用程序使用sendfile()函数来转移大量数据。应用协议通常要求发送某些信息来预先解释数据,这些信息其实就是报头内容。典型情况下报头很 小,而且套接字上设置了TCP_NODELAY。

    有报头的包将被立即传输,在某些情况下(取决于内部的包计数器),因为这个包成功地被对方收到后需要请求 对方确认。

    这样,大量数据的传输就会被推迟而且产生了不必要的网络流量交换。 但是,如果我们在套接字上设置了TCP_CORK(可以比喻为在管道上插入“塞子”)选项,具有报头的包就会填补大量的数据,所有的数据都根据大小自动地 通过包传输出去。当数据传输完成时,最好取消TCP_CORK 选项设置给连接“拔去塞子”以便任一部分的帧都能发送出去。这同“塞住”网络连接同等重要。

    总而言之,如果你肯定能一起发送多个数据集合(例如HTTP响应的头和正文),那么我们建议你设置TCP_CORK选项,这样在这些数据之间不存在延迟。 能极大地有益于WWW、FTP以及文件服务器的性能,同时也简化了你的工作。

--------------------------------华丽的分割线---------------------------------------------------

SO_REUSEADDR

    套接字选项:使两个server socket可以监听同一个端口 默认情况下,套接字不同一个正在使用的本地地址绑定到一起。但在少数情况下,仍有必要以这种方式,来实现对一个地址的重复利用。

    通过第7章的学习,大家已 经知道,每个连接都是通过它的本地及远程地址的组合,“独一无二”地标识出来的。针对我们想要连接的地址,只要能用极其细微的差异(比如TCP/IP中采用不同的端口号),来维持这种“独一无二”或者“唯一”的特点,绑定便是允许的。

    唯一例外的是监听套接字。两个独立的套接字不可与同一个本地接口 (在TCP/IP的情况下,则是端口)绑定到一起,以等待进入的连接通知。

    假定两个套接字都在同一个端口上进行监听,那么到底由谁来接收一个进入连接通知呢?对于这个问题,目前尚无一种正式规范提出了解决方案。

    在TCP的环境下,假如服务器关闭,或异常退出,造成本地地址和端口均进入TIME_WAIT状态,那么SO_REUSEADDR 这个套接字选项便显得非常有用。

    在TIME_WAIT状态下,其他任何套接字都不能与那个端口绑定到一起。但假若设置了该选项,服务器便可在重新启动之后,在相同的本地接口及端口上进行监听。

    将服务端socket套接字设置上SO_REUSEADDR属性,代码如下:

//设置socket套接字的属性:允许多个设备在同一个本地网中监听同一下端口
int one = 1;
if (sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) {
    printf("setsockopt SO_REUSEADDR error\n");
    close(sock);
    return;
} 
 

    这么设置套接字的作用是:允许两个server端的套接字在同一个本地网段中监听同一个端口.

--------------------------------华丽的分割线---------------------------------------------------

SO_KEEPALIVE

    保持连接检测对方主机是否崩溃,避免(服务器)永远阻塞于TCP连接的输入。

    设置该选项后,如果2小时内在此套接口的任一方向都没有数据交换,TCP就自 动给对方 发一个保持存活探测分节(keepalive probe)。这是一个对方必须响应的TCP分节.它会导致以下三种情况:

  • 对方接收一切正常:以期望的ACK响应。2小时后,TCP将发出另一个探测分 节。

  • 对方已崩溃且已重新启动:以RST响应。套接口的待处理错误被置为ECONNRESET,套接 口本身则被关闭。

  • 对方无任何响应:源自berkeley的TCP发送另外8个探测分节,相隔75秒一个,试图得到一个响应。在发出第一个探测分节11分钟 15秒后若仍无响应就放弃。
    套接口的待处理错误被置为ETIMEOUT,套接口本身则被关闭。如ICMP错误是“host unreachable(主机不可达)”,说明对方主机并没有崩溃,但是不可达,这种情况下待处理错误被置为 EHOSTUNREACH。
    在该书的第158页有更详细的描述。

     根据上面的介绍我们可以知道对端以一种非优雅的方式断开连接的时候,我们可以设置SO_KEEPALIVE属性使得我们在2小时以后发现对方的TCP连接 是否依然存在。

keepAlive = 1; 
Setsockopt(listenfd, SOL_SOCKET, SO_KEEPALIVE, (void*)&keepAlive, sizeof(keepAlive));
 

    如果我们不能接受如此之长的等待时间,从TCP-Keepalive-HOWTO上可以知道一共有两种方式可以设置,一种是修改内核关于网络方面的配置参 数,另外一种就是SOL_TCP字段的TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_KEEPCNT三个选项。

猜你喜欢

转载自11lingxian.iteye.com/blog/606782