在socket编程中我们会经常用到setsockopt这个函数,那么本节我们将对这个函数的参数和使用做说明:

首先看下函数原型:

int setsockopt( int socket, int level, int option_name,const void *option_value, size_t ,ption_len);

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

  1.     SO_DEBUG,打开或关闭调试信息。
        当option_value不等于0时,打开调试信息,否则,关闭调试信息。它实际所做的工作是在sock->sk->sk_flag中置 SOCK_DBG(第10)位,或清SOCK_DBG位。
  2.     SO_REUSEADDR,打开或关闭地址复用功能。
        当option_value不等于0时,打开,否则,关闭。它实际所做的工作是置sock->sk->sk_reuse为1或0。
  3.     SO_DONTROUTE,打开或关闭路由查找功能。
        当option_value不等于0时,打开,否则,关闭。它实际所做的工作是在sock->sk->sk_flag中置或清SOCK_LOCALROUTE位。
  4.     SO_BROADCAST,允许或禁止发送广播数据。
        当option_value不等于0时,允许,否则,禁止。它实际所做的工作是在sock->sk->sk_flag中置或清SOCK_BROADCAST位。
  5.     SO_SNDBUF,设置发送缓冲区的大小。
        发送缓冲区的大小是有上下限的,其上限为256 * (sizeof(struct sk_buff) + 256),下限为2048字节。该操作将sock->sk->sk_sndbuf设置为val * 2,之所以要乘以2,是防
    止大数据量的发送,突然导致缓冲区溢出。最后,该操作完成后,因为对发送缓冲的大小 作了改变,要检查sleep队列,如果有进程正在等待写,将它们唤醒。
  6.     SO_RCVBUF,设置接收缓冲区的大小。
        接收缓冲区大小的上下限分别是:256 * (sizeof(struct sk_buff) + 256)和256字节。该操作将sock->sk->sk_rcvbuf设置为val * 2。
  7.     SO_KEEPALIVE,套接字保活。
        如果协议是TCP,并且当前的套接字状态不是侦听(listen)或关闭(close),那么,当option_value不是零时,启用TCP保活定时 器,否则关闭保活定时器。对于所有协议,该操
    作都会根据option_value置或清 sock->sk->sk_flag中的 SOCK_KEEPOPEN位。
  8.     SO_OOBINLINE,紧急数据放入普通数据流。
        该操作根据option_value的值置或清sock->sk->sk_flag中的SOCK_URGINLINE位。
  9.     SO_NO_CHECK,打开或关闭校验和。
        该操作根据option_value的值,设置sock->sk->sk_no_check。
  10.     SO_PRIORITY,设置在套接字发送的所有包的协议定义优先权。Linux通过这一值来排列网络队列。
        这个值在0到6之间(包括0和6),由option_value指定。赋给sock->sk->sk_priority。
  11.     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。
  12.     SO_PASSCRED,允许或禁止SCM_CREDENTIALS 控制消息的接收。
        该选项根据option_value的值,清或置sock->sk->sk_flag中的SOCK_PASSCRED位。
  13.     SO_TIMESTAMP,打开或关闭数据报中的时间戳接收。
        该选项根据option_value的值,清或置sock->sk->sk_flag中的SOCK_RCVTSTAMP位,如果打开,则还需设sock->sk->sk_flag中的SOCK_TIMESTAMP位,同时,将全局变量
    netstamp_needed加1。
  14.     SO_RCVLOWAT,设置接收数据前的缓冲区内的最小字节数。
        在Linux中,缓冲区内的最小字节数是固定的,为1。即将sock->sk->sk_rcvlowat固定赋值为1。
  15.     SO_RCVTIMEO,设置接收超时时间。
        该选项最终将接收超时时间赋给sock->sk->sk_rcvtimeo。
  16.     SO_SNDTIMEO,设置发送超时时间。
        该选项最终将发送超时时间赋给sock->sk->sk_sndtimeo。
  17.     SO_BINDTODEVICE,将套接字绑定到一个特定的设备上。
        该选项最终将设备赋给sock->sk->sk_bound_dev_if。
  18.  SO_ATTACH_FILTER和SO_DETACH_FILTER。
        关于数据包过滤,它们最终会影响sk->sk_filter。
        

以上所介绍的都是在SOL_SOCKET层的一些套接字选项,如果超出这个范围, 给出一些不在这一level的选项作为参数,最终会得到ENOPROTOOPT的返回值。但以上的分析仅限。



  • SO_REUSEADDR

此参数经常用于当socket正在关闭,处于TIME_WAIT的状态,而此时你又想继续重用该socket,你可以私用此参数,否则你在调用bind接口的时候会出现bind failed: Address already in use:


此时为了解决此问题,我们就可以使用SO_REUSEADDR参数。

BOOL bReuseaddr=TRUE;
setsockopt(s,SOL_SOCKET ,SO_REUSEADDR,(const char*)&bReuseaddr,sizeof(BOOL));

  • SO_DONTLINGER

如果要已经处于连接状态的soket在调用closesocket后强制关闭,不经历

TIME_WAIT的过程:

BOOL bDontLinger = FALSE;
setsockopt(s,SOL_SOCKET,SO_DONTLINGER,(const char*)&bDontLinger,sizeof(BOOL));


  • SO_SNDTIMEO和 SO_RCVTIMEO

 在send(),recv()过程中有时由于网络状况等原因,发收不能预期进行,而设置收发时限:

int nNetTimeout=5000;//5秒
//发送时限
setsockopt(socket,SOL_S0CKET,SO_SNDTIMEO,(char *)&nNetTimeout,sizeof(int));
//接收时限
setsockopt(socket,SOL_S0CKET,SO_RCVTIMEO,(char *)&nNetTimeout,sizeof(int));

  • SO_RCVBUF和SO_SNDBUF

在send()的时候,返回的是实际发送出去的字节(同步)或发送到socket缓冲区的字节(异步);系统默认的状态发送和接收一次为8688字节(约为8.5K);

在实际的过程中发送数据和接收数据量比较大,可以设置socket缓冲区,而避免了send(),recv()不断的循环收发:

//设置socket接收或者发送缓冲区大小
inline int set_socket_bufsize(SOCKET sock, bool isRead, int netbufsize)
{
int opt_name = isRead ? SO_RCVBUF : SO_SNDBUF;
int nBufSize = netbufsize;
return ::setsockopt(sock, SOL_SOCKET, opt_name, reinterpret_cast<char*>(&nBufSize), sizeof(nBufSize));
}

如果在发送数据的时,希望不经历由系统缓冲区到socket缓冲区的拷贝而影响程序的性能:


int nZero=0;
setsockopt(socket,SOL_S0CKET,SO_SNDBUF,(char *)&nZero,sizeof(nZero));


同上在recv()完成上述功能(默认情况是将socket缓冲区的内容拷贝到系统缓冲区):


int nZero=0;
setsockopt(socket,SOL_S0CKET,SO_RCVBUF,(char *)&nZero,sizeof(int));



  • SO_BROADCAST

一般在发送UDP数据报的时候,希望该socket发送的数据具有广播特性:

BOOL bBroadcast=TRUE;
setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const char*)&bBroadcast,sizeof(BOOL));

  • SO_CONDITIONAL_ACCEPT

在client连接服务器过程中,如果处于非阻塞模式下的socket在connect()的过程中可以设置connect()延时,直到accpet()被呼叫(本函数设置只有在非阻塞的过程中有显著的作用,在阻塞的函数调用中作用不大)

BOOL bConditionalAccept=TRUE;
setsockopt(s,SOL_SOCKET,SO_CONDITIONAL_ACCEPT,(const char*)&bConditionalAccept,sizeof(BOOL));


  • SO_LINGER

如果在发送数据的过程中(send()没有完成,还有数据没发送)而调用了closesocket(),以前我们一般采取的措施是"从容关闭"shutdown,但是数据是肯定丢失了,如何设置让程序满足具体应用的要求(即让没发完的数据发送出去后在关闭socket)?

struct linger {


u_short l_onoff;
u_short l_linger;
};
linger m_sLinger;
m_sLinger.l_onoff=1;//(在closesocket()调用,但是还有数据没发送完毕的时候容许逗留)
// 如果m_sLinger.l_onoff=0;则功能和2.)作用相同;
m_sLinger.l_linger=5;//(容许逗留的时间为5秒)
setsockopt(s,SOL_SOCKET,SO_LINGER,(const char*)&m_sLinger,sizeof(linger));


setsockopt()支持下列选项。其中“类型”表明optval所指数据的类型。

选项     

   类型   

意义

SO_BROADCAST 

BOOL

允许套接口传送广播信息。

SO_DEBUG 

BOOL

记录调试信息。

SO_DONTLINER 

BOOL

不要因为数据未发送就阻塞关闭操作。设置本选项相当于将SO_LINGER的l_onoff元素置为零。

SO_DONTROUTE 

BOOL 

禁止选径;直接传送。

SO_KEEPALIVE BOOL


发送“保持活动”包。

SO_LINGER  

struct linger FAR*

如关闭时有未发送数据,则逗留。

SO_OOBINLINE 

BOOL

在常规数据流中接收带外数据。

SO_RCVBUF 

int 

为接收确定缓冲区大小。

SO_REUSEADDR 

BOOL

允许套接口和一个已在使用中的地址捆绑(参见bind())。

SO_SNDBUF 

int

指定发送缓冲区大小。

TCP_NODELAY 

BOOL 

禁止发送合并的Nagle算法。

setsockopt()不支持的BSD选项有:

选项名  

类型 

意义

SO_ACCEPTCONN

BOOL 

套接口在监听。

SO_ERROR 

int 

获取错误状态并清除。

SO_RCVLOWAT 

int 

接收低级水印。

SO_RCVTIMEO

int 

接收超时。

SO_SNDLOWAT 

int 

发送低级水印。

SO_SNDTIMEO 

int 

发送超时。

SO_TYPE     

int 

套接口类型。

IP_OPTIONS    


在IP头中设置选项。

返回值:
     若无错误发生,setsockopt()返回0。否则的话,返回SOCKET_ERROR错误,应用程序可通过WSAGetLastError()获取相应错误代码。
错误代码:

  • WSANOTINITIALISED:在使用此API之前应首先成功地调用WSAStartup()。
  • WSAENETDOWN:WINDOWS套接口实现检测到网络子系统失效。
  • WSAEFAULT:optval不是进程地址空间中的一个有效部分。
  • WSAEINPROGRESS:一个阻塞的WINDOWS套接口调用正在运行中。
  • WSAEINVAL:level值非法,或optval中的信息非法。
  • WSAENETRESET:当SO_KEEPALIVE设置后连接超时。
  • WSAENOPROTOOPT:未知或不支持选项。其中,SOCK_STREAM类型的套接口不支持SO_BROADCAST选项,SOCK_DGRAM 类型的套接口不支持SO_DONTLINGER 、SO_KEEPALIVE、SO_LINGER和SO_OOBINLINE选项。
  • WSAENOTCONN:当设置SO_KEEPALIVE后连接被复位。
  • WSAENOTSOCK:描述字不是一个套接口。