Linux socket 编程细节

来源:互联网 发布:怎么下载电脑软件 编辑:程序博客网 时间:2024/04/30 14:25

Q: 编写 TCP/SOCK_STREAM 服务程序时,SO_REUSEADDR到底什么意思?

A: 这个套接字选项通知内核,如果端口忙,但TCP状态位于 TIME_WAIT ,可以重用端口。如果端口忙,而TCP状态位于其他状态,重用端口时依旧得到一个错误信息,指明"地址已经使用中"。如果你的服务程序停止后想立即重启,而新套接字依旧使用同一端口,此时 SO_REUSEADDR 选项非常有用。必须意识到,此时任何非期望数据到达,都可能导致服务程序反应混乱,不过这只是一种可能,事实上很不可能。

一个套接字由相关五元组构成,协议、本地地址、本地端口、远程地址、远程端口。SO_REUSEADDR 仅仅表示可以重用本地本地地址、本地端口,整个相关五元组还是唯一确定的。所以,重启后的服务程序有可能收到非期望数据。必须慎重使用 SO_REUSEADDR 选项。

Q:  O_NONBLOCK 与 O_NDELAY 有何不同?

A: O_NONBLOCKO_NDELAY所产生的结果都是使I/O变成非搁置模式(non-blocking),在读取不到数据或是写入缓冲区已满会马上return,而不会搁置程序动作,直到有数据或写入完成。

它们的差别在于设立O_NDELAY会使I/O函式马上回传0,但是又衍生出一个问题,因为读取到档案结尾时所回传的也是0,这样无法得知是哪中情况;因此,O_NONBLOCK就产生出来,它在读取不到数据时会回传-1,并且设置errnoEAGAIN

不过需要注意的是,在GNU CO_NDELAY只是为了与BSD的程序兼容,实际上是使用O_NONBLOCK作为宏定义,而且O_NONBLOCK除了在ioctl中使用,还可以在open时设定。

 

Socket描述符选项[SOL_SOCKET]

 

Socket描述符选项[SOL_SOCKET]

#include <sys/socket.h>

     int setsockopt( int socket, int level, int option_name,

                         const void *option_value, size_t option_len);

 

第一个参数socket是套接字描述符。第二个参数level是被设置的选项的级别,如果想要在套接字级别上设置选项,就必须把level设置为SOL_SOCKET。 option_name指定准备设置的选项,option_name可以有哪些取值,这取决于level,以linux 2.6内核为例(在不同的平台上,这种关系可能会有不同),在套接字级别上(SOL_SOCKET),option_name可以有以下取 值:

 

SO_DEBUG,打开或关闭调试信息。

             当option_value不等于0时,打开调试信息,否则,关闭调试信息。它实际所做的工作是在sock->sk->sk_flag中置 SOCK_DBG(第10)位,或清SOCK_DBG位。

SO_REUSEADDR,打开或关闭地址复用功能。

             当option_value不等于0时,打开,否则,关闭。它实际所做的工作是置sock->sk->sk_reuse为1或0。

SO_DONTROUTE,打开或关闭路由查找功能。

             当option_value不等于0时,打开,否则,关闭。它实际所做的工作是在sock->sk->sk_flag中置或清 SOCK_LOCALROUTE位。

SO_BROADCAST,允许或禁止发送广播数据。

             当option_value不等于0时,允许,否则,禁止。它实际所做的工作是在sock->sk->sk_flag中置或清 SOCK_BROADCAST位。

SO_SNDBUF,设置发送缓冲区的大小。

             发送缓冲区的大小是有上下限的,其上限为256 * (sizeof(struct sk_buff) + 256),下限为2048字节。该操作将sock->sk->sk_sndbuf设置为val * 2,之所以要乘以2,是防大数据量的发送,突然导致缓冲区溢出。最后,该操作完成后,因为对发送缓冲的大小 作了改变,要检查sleep队列,如果有进程正在等待写,将它们唤醒。

SO_RCVBUF,设置接收缓冲区的大小。

             接收缓冲区大小的上下限分别是:256 * (sizeof(struct sk_buff) + 256)和256字节。该操作将sock->sk->sk_rcvbuf设置为val * 2。

SO_KEEPALIVE,套接字保活。

              如果协议是TCP,并且当前的套接字状态不是侦听(listen)或关闭(close),那么,当option_value不是零时,启用TCP保活定时 器,否则关闭保活定时器。对于所有协议,该操作都会根据option_value置或清 sock->sk->sk_flag中的 SOCK_KEEPOPEN位。

SO_OOBINLINE,紧急数据放入普通数据流。

             该操作根据option_value的值置或清sock->sk->sk_flag中的SOCK_URGINLINE位。

SO_NO_CHECK,打开或关闭校验和。

             该操作根据option_value的值,设置sock->sk->sk_no_check。

SO_PRIORITY,设置在套接字发送的所有包的协议定义优先权。Linux通过这一值来排列网络队列。

              这个值在0到6之间(包括0和6),由option_value指定。赋给sock->sk->sk_priority。

SO_LINGER,如果选择此选项, close或 shutdown将等到所有套接字里排队的消息成功发送或到达延迟时间后>才会返回. 否则, 调用将立即返回。

              该选项的参数(option_value)是一个linger结构:

        struct linger {

            int   l_onoff;    /* 延时状态(打开/关闭) */

            int   l_linger;   /* 延时多长时间 */

        };

    如果linger.l_onoff值为0(关闭),则清 sock->sk->sk_flag中的SOCK_LINGER位;否则,置该位,并赋sk->sk_lingertime值为 linger.l_linger。

SO_PASSCRED,允许或禁止SCM_CREDENTIALS 控制消息的接收。

             该选项根据option_value的值,清或置sock->sk->sk_flag中的SOCK_PASSCRED位。

SO_TIMESTAMP,打开或关闭数据报中的时间戳接收。

             该选项根据option_value的值,清或置sock->sk->sk_flag中的SOCK_RCVTSTAMP位,如果打开,则还需 设sock->sk->sk_flag中的SOCK_TIMESTAMP位,同时,将全局变量netstamp_needed加1。

SO_RCVLOWAT,设置接收数据前的缓冲区内的最小字节数。

              在Linux中,缓冲区内的最小字节数是固定的,为1。即将sock->sk->sk_rcvlowat固定赋值为1。

SO_RCVTIMEO,设置接收超时时间。

              该选项最终将接收超时时间赋给sock->sk->sk_rcvtimeo。

SO_SNDTIMEO,设置发送超时时间。

              该选项最终将发送超时时间赋给sock->sk->sk_sndtimeo。

SO_BINDTODEVICE,将套接字绑定到一个特定的设备上。

              该选项最终将设备赋给sock->sk->sk_bound_dev_if。

SO_ATTACH_FILTER和SO_DETACH_FILTER。

              关于数据包过滤,它们最终会影响sk->sk_filter。

   

以上所介绍的都是在SOL_SOCKET层的一些套接字选项,如果超出这个范围, 给出一些不在这一level的选项作为参数,最终会得到- ENOPROTOOPT的返回值。但以上的分析仅限于这些选项对sock-sk的值的影响,这些选项真正如何发挥作用,我们的探索道路 将漫漫其修远。

 

原创粉丝点击