getsockopt()和setsockopt()函数详解

功能描述:
获取或者 设置 与某个套接字关联的选项。选项可能存在于多层 协议 中,它们总会出现在最上面的套接字层。
当操作套接字选项时,选项位于的层和选项的名称必须给出。
为了操作套接字层的选项,应该将层的值指定为SOL_SOCKET。
为了操作其它层的选项,控制选项的合适协议号必须给出。
例如,为了表示一个选项由
TCP 协议解析,层应该设定为协议 号TCP。


用法:
#include
#include

int getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen);

int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen);

参数:  
sock:将要被设置或者获取选项的套接字。
level:选项所在的协议层。
optname:需要访问的选项名。
optval:对于getsockopt(),指向返回选项值的缓冲。
            对于setsockopt(),指向包含新选项值的缓冲。
optlen:对于getsockopt(),作为入口参数时,选项值的最大长度。作为出口参数时,选项值的实际长度。
            对于setsockopt(),现选项的长度。


返回说明:  


成功执行时,返回0。失败返回-1,
errno被设为以下的某个值 
 
EBADF:               sock不是有效的文件描述词
EFAULT:             optval指向的内存并非有效的进程空间
EINVAL:               在调用setsockopt()时,optlen无效
ENOPROTOOPT:指定的协议层不能识别选项
ENOTSOCK:        sock描述的不是套接字


参数详细说明:

level指定控制套接字的层次.可以取三种值:
  1)SOL_SOCKET:   通用套接字选项.
  2)IPPROTO_IP:      IP选项.
  3)IPPROTO_TCP:  TCP选项. 

optname指定控制的方式(选项的名称),我们下面详细解释 

optval获得或者是设置套接字选项.根据选项名称的数据类型进行转换 


选项名称        说明                  数据类型
========================================================================
            SOL_SOCKET
------------------------------------------------------------------------
SO_BROADCAST      允许发送广播数据            int
SO_DEBUG        允许调试                int
SO_DONTROUTE      不查找路由               int
SO_ERROR        获得套接字错误             int
SO_KEEPALIVE       保持连接                int
SO_LINGER        延迟关闭连接              struct linger
SO_OOBINLINE       带外数据放入正常数据流         int
SO_RCVBUF         接收缓冲区大小             int
SO_SNDBUF         发送缓冲区大小             int
SO_RCVLOWAT        接收缓冲区下限             int
SO_SNDLOWAT      发送缓冲区下限             int
SO_RCVTIMEO     接收超时                struct timeval
SO_SNDTIMEO        发送超时                struct timeval
SO_REUSERADDR     允许重用本地地址和端口         int
SO_TYPE         获得套接字类型             int
SO_BSDCOMPAT       与BSD系统兼容              int
========================================================================
            IPPROTO_IP
------------------------------------------------------------------------
IP_HDRINCL       在数据包中包含IP首部          int
IP_OPTINOS       IP首部选项               int
IP_TOS          服务类型
IP_TTL           生存时间                int
========================================================================
            IPPRO_TCP
------------------------------------------------------------------------
TCP_MAXSEG       TCP最大数据段的大小           int
TCP_NODELAY       不使用Nagle算法             int
========================================================================

SO_RCVBUF和SO_SNDBUF每个套接口都有一个发送缓冲区和一个接收缓冲区,使用这两个套接口选项可以改变缺省缓冲区大小。

// 接收缓冲区
int nRecvBuf=32*1024;         //设置为32K
setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));


//发送缓冲区
int nSendBuf=32*1024;//设置为32K
setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int));

注意:

 当设置TCP套接口接收缓冲区的大小时,函数调用顺序是很重要的,因为TCP的窗口规模选项是在建立连接时用SYN与对方互换得到的。
对于客户端,O_RCVBUF选项必须在connect之前设置;
对于
服务羰,SO_RCVBUF选项必须在listen前设置。

结合原理说明:

1.每个套接口都有一个发送缓冲区和一个接收缓冲区。
接收缓冲区被TCP和UDP用来将接收到的数据一直保存到由
应用进程来读。
TCP:
       TCP通告另一端的窗口大小。 TCP套接口接收缓冲区不可能溢出,因为对方不允许发出超过所通告窗口大小的数据。
       这就是TCP的流量控制,如果对方无视窗口大小而发出了超过窗口大小的数据,则接 收方TCP将丢弃它。
UDP:
       当接收到的数据报装不进套接口接收缓冲区时,此数据报就被丢弃。
       UDP是没有流量控制的;快的发送者可以很容易地就淹没慢的接收者,导致接收方的UDP丢弃数据报。

 
2.我们经常听说tcp协议的三次握手,但三次握手到底是什么,其细节是什么,为什么要这么做呢?

        第一次:客户端发送连接请求给服务器,服务器接收;
        第二次:服务器返回给客户端一个确认码,附带一个从服务器到客户端的连接请求,客户机接收,确认客户端到服务器的连接.
        第三次:客户机返回服务器上次发送请求的确认码,服务器接收,确认服务器到客户端的连接.
我们可以看到:
        1. tcp的每个连接都需要确认.
        2. 客户端到服务器和服务器到客户端的连接是独立的.
我们再想想tcp协议的特点:连接的,可靠的,全双工的,实际上tcp的三次握手正是为了保证这些特性的实现.


3.setsockopt的用法

1.closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket:
BOOL bReuseaddr=TRUE;
setsockopt(s,SOL_SOCKET ,SO_REUSEADDR,(const char*)&bReuseaddr,sizeof(BOOL));


2. 如果要已经处于连接状态的soket在调用closesocket后强制关闭,不经历TIME_WAIT的过程:
BOOL bDontLinger = FALSE;
setsockopt(s,SOL_SOCKET,SO_DONTLINGER,(const char*)&bDontLinger,sizeof(BOOL));


3.在send(),recv()过程中有时由于网络状况等原因,发收不能预期进行,而设置收发时限:
int nNetTimeout=1000;//1秒
//发送时限
setsockopt(socket,SOL_S0CKET,SO_SNDTIMEO(char *)&nNetTimeout,sizeof(int));
//接收时限
setsockopt(socket,SOL_S0CKET,SO_RCVTIMEO,(char *)&nNetTimeout,sizeof(int));


4.在send()的时候,
 返回的是实际发送出去的字节(同步)
 或发送到socket缓冲区的字节
(异步);
系统默认的状态发送和接收一次为8688字节(约为8.5K);
在实际的过程中发送数据
和接收数据量比较大,可以设置socket缓冲区,而避免了send(),recv()不断的循环收发:
// 接收缓冲区
int nRecvBuf=32*1024;//设置为32K
setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));
//发送缓冲区
int nSendBuf=32*1024;//设置为32K
setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int));


5. 如果在发送数据的时,希望不经历由系统缓冲区到socket缓冲区的拷贝而影响程序的性能:
int nZero=0;
setsockopt(socket,SOL_S0CKET,SO_SNDBUF(char *)&nZero,sizeof(nZero));


6.同上在recv()完成上述功能(默认情况是将socket缓冲区的内容拷贝到系统缓冲区):
int nZero=0;
setsockopt(socket,SOL_S0CKET,SO_RCVBUF(char *)&nZero,sizeof(int));


7.一般在发送UDP数据报的时候,希望该socket发送的数据具有广播特性:
BOOL bBroadcast=TRUE;
setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const char*)&bBroadcast,sizeof(BOOL));


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

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


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

 

注意:两种套接口的选项:
一种是布尔型选项,允许或禁止一种特性;
另一种是整形或结构选项。
允许一个布尔型选项,则将optval指向非零整形数;
禁止一个选项optval指向一个等于零的整形数。
对于布尔型选项,optlen应等于sizeof(int);对其他选项,optval指向包含所需选项的整形数或结构,而optlen则为整形数或结构的长度。
SO_LINGER选项用于控制下述情况的行动:套接口上有排队的待发送数据,且closesocket()调用已执行。
参见closesocket()函数中关于SO_LINGER选项对closesocket()语义的影响。
应用程序通过创建一个linger结构来设置相应的操作特性:

   struct linger {
   int l_onoff;
   int l_linger;
 };
为了允许SO_LINGER,应用程序应将l_onoff设为非零,将l_linger设为零或需要的超时值(以秒为单位),然后调用setsockopt()。
为了允许SO_DONTLINGER(亦即禁止SO_LINGER),l_onoff应设为零,然后调用
setsockopt()。
 
缺省条件下,一个套接口不能与一个已在使用中的本地地址捆绑(参见bind())。
但有时会需要“重用”地址。因为每一个连接都由本地地址和远端地址的组合唯一确定,所以只要远端地址不同,两个套接口与一个地址捆绑并无大碍。
为了通知套接口实现不要因为一个地址已被一个套接口使用就不让它与另一个套接口捆绑,
应用程序可在bind()调用前先设置SO_REUSEADDR选项。
请注意仅在bind()调用时该选项才被解释;
故此无需(但也无害)将一个不会共用地址的套接口设置该选项,或者在bind()对这个或其他套接口无影响情况下设置或清除这一选项。 

 
一个应用程序可以通过打开SO_KEEPALIVE选项,使得套接口实现在TCP连接情况下允许使用“保持活动”包。
一个套接口实现并不是必需支持“保持活动”,但是如果支持的话,具体的语义将与实现有关。


TCP_NODELAY选项禁止Nagle算法

Nagle算法通过将未确认的数据存入缓冲区直到蓄足一个包一起发送的方法,来减少主机发送的零碎小数据包的数目。
但对于某些应用来说,这种算法将降低系统性能。
所以TCP_NODELAY可用来将此算法关闭。
应用程序编写者只有在确切了解它的效果并确实需要的情况下,才设置TCP_NODELAY选项,因为设置后对网络性能有明显的负面影响。
TCP_NODELAY是唯一使用IPPROTO_TCP层的选项,其他所有选项都使用SOL_SOCKET层。


如果设置了SO_DEBUG选项,套接口供应商被鼓励(但不是必需)提供输出相应的调试信息。
但产生调试信息的机制以及调试信息的形式已超出本规范的讨论范围。

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

 

转载出处:http://blog.csdn.net/chinafe/archive/2008/12/15/3517537.aspx
转载出处:http://blog.csdn.net/xioahw/archive/2009/04/08/4056514.aspx

  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
《TCP/IP详解·卷2:实现》完整而详细地介绍了TCP/IP协议是如何实现的。书中给出了约500个图例,15000行实际操作的C代码,采用举例教学的方法帮助你掌握TCP/IP实现。《TCP/IP详解·卷2:实现》不仅说明了插口API和协议族的关系以及主机实现与路由器实现的差别。还介绍了4.4BSD-Lite版的新的特点。《TCP/IP详解·卷2:实现》适用于希望理解TCP/IP协议如何实现的人,包括编写网络应用程序的程序员以及利用TCP/IP维护计算机网络的系统管理员。 目录 · · · · · · 第一章 概述 1.1 引言 1.2 源代码表示 1.3 历史 1.4 应用编程接口 1.5 程序示例 1.6 系统调用和库函数 1.7 描述符 1.8 网络实现概述 1.9 mbuf与输出处理 1.10 输入处理 1.11 网络实现概述 1.12 中断级别与并发 1.13 源代码组织 1.14 测试网络 1.15 小结 第二章 mduf:存储器缓存 2.1 引言 2.2 代码介绍 2.3 mduf的定义 2.4 mduf结构 2.5 简单的mduf宏和函数 2.6 m_devget和m_pullup函数 2.7 mduf宏和函数的小结 2.8 Net/3联网数据结构小结 2.9 m_copy和簇引用记数 2.10 其他选择 2.11 小结 第三章 接口层 3.1 引言 3.2 代码介绍 3.3 ifnet结构 3.4 ifaddr结构 3.5 sockaddr结构 3.6 ifnet与ifaddr的专用化 3.7 网络初始化概述 3.8 以太网初始化 3.9 SLIP初始化 3.10 环回初始化 3.11 if_attach函数 3.12 ifinit函数 3.13 小结 第四章 接口:以太网 4.1 引言 4.2 代码介绍 4.3 以太网接口 4.4 ioctl系统调用 4.5 小结 第五章 接口:SLIP和环回 5.1 引言 5.2 代码介绍 5.3 SLIP接口 5.4 环回接口 5.5 小结 第六章 IP编址 6.1 引言 6.2 代码介绍 6.3 接口和地址小结 6.4 sockaddr_in结构 6.5 in_ifaddr结构 6.6 地址指派 6.7 接口ioctl处理 6.8 internet实用函数 6.9 ifnet实用函数 6.10 小结 第七章 域和协议 7.1 引言 7.2 代码介绍 7.3 domain结构 7.4 protosw结构 7.5 IP的domain和protosw结构 7.6 pffindproto和pffindtype函数 7.7 pfctlinput函数 7.8 IP初始化 7.9 sysctl系统调用 7.10 小结 第八章 IP:网际协议 8.1 引言 8.2 代码介绍 8.3 IP分组 8.4 输入处理:ipintr函数 8.5 转发:ip_forward函数 8.6 输出处理:ip_output函数 8.7 Internet检验和:in_cksum函数 8.8 setsockoptgetsockopt系统调用 8.9 ip_sysctl函数 8.10 小结 第九章 IP选项处理 9.1 引言 9.2 代码介绍 9.3 选项格式 9.4 ip_dooptions函数 9.5 记录路由选项 9.6 源站和记录路由选项 9.7 时间戳选项 9.8 ip_insertoptions函数 9.9 ip_pcbopts函数 9.10 一些限制 9.11 小结 第十章 IP的分片与重装 10.1 引言 10.2 代码介绍 10.3 分片 10.4 ip_optcopy函数 10.5 重装 10.6 ip_optcopy函数 10.7 ip_slowtimo函数 10.8 小结 第十一章 ICMP:Internet控制报文协议 第十二章 IP多播 第十三章 IGMP:Internet组管理协议 第十四章 IP多播选路 第十五章 插口层 第十六章 插口I/O 第十七章 插口选项 第十八章 Radix树路由表 第十九章 选路请求和选路消息 第二十章 选路接口 第二十一章 ARP:地址解析协议 第二十二章 协议控制块 第二十三章 UDP:用户数据报协议 第二十四章 TCP:传输控制协议 第二十五章 TCP的定时器 第二十六章 TCP输出 第二十七章 TCP的函数 第二十八章 TCP的输入 第二十九章 TCP的输入(续) 第三十章 TCP的用户需求 第三十一章 BPF:BSD分组过滤程序 第三十二章 原始IP 结束语 附录A 部分习题的解答 附录B 源代码的获取 附录C RFC 1122的有关内容 参考文献
### 回答1: getsockopt/setsockopt函数是用于设置和获取套接字选项的函数。其中,getsockopt用于获取指定套接字选项的值,而setsockopt用于设置指定套接字选项的值。这两个函数在网络编程中经常被用到。 ### 回答2: getsockoptsetsockopt函数是用来获取和设置套接字选项的API函数,在网络编程中十分常见。套接字选项是一个可选的参数,它允许用户设置套接字的某些属性,例如超时时间、是否启用广播、缓冲区大小等等。 getsockopt函数用于获取套接字选项的当前值。它需要传入以下参数: 1. sockfd: 套接字描述符; 2. level: 选项定义的协议层; 3. optname: 需要获取的选项名称; 4. optval: 指向一个缓冲区,用于存储获取到的选项值; 5. optlen: 缓冲区的大小。 setsockopt函数用于设置套接字选项的值。它需要传入以下参数: 1. sockfd: 套接字描述符; 2. level: 选项定义的协议层; 3. optname: 需要设置的选项名称; 4. optval: 指向一个缓冲区,用于存储需要设置的选项值; 5. optlen: 缓冲区的大小。 需要注意的是,不同的协议层和选项名称对应的值有所不同。可以通过man手册或者网络查找相关资料来获取更详细的信息。 这些函数在网络编程中经常被使用,例如可以通过setsockopt函数设置套接字的超时时间,当网络I/O操作超过指定时间时,会自动返回一个超时错误;也可以通过getsockopt函数来获取当前是否启用了广播选项等等。 总之,getsockoptsetsockopt函数可以让我们更方便地控制和监控套接字的行为,提高网络通信的效率和可靠性。 ### 回答3: getsockoptsetsockopt函数都是与网络编程相关的系统调用函数,它们用于控制和获取套接字选项。在进行网络编程时,我们需要使用这两个函数来调整套接字的设置,以便实现更好的网络通信效果。 具体地说,setsockopt函数可以设置某个套接字的选项值,例如设置套接字的发送和接收缓冲区大小、设置是否对数据包进行分片等等。而getsockopt函数则可以获取某个套接字的选项值,以便进行校验或者输出日志等功能。 关于参数方面,getsockoptsetsockopt函数都需要传入当前操作的套接字句柄,以及要设置或者获取的选项值。setsockopt函数还需要传入对应选项值的指针和大小;而getsockopt函数需要传入一个指向缓冲区的指针,用来接收获取的选项值和大小。 需要注意的是,每个选项都有对应的协议层级,而不同的选项可能只在特定协议的套接字上有效。因此,在使用这两个函数时,需要注意选项的协议层级,以及操作的套接字所使用的协议类型,避免出现无法设置或获取选项值的情况。 同时,getsockoptsetsockopt函数也有一定的返回值,setsockopt函数返回是否设置成功,而getsockopt函数返回获取的选项值的长度。在使用时,我们需要对返回值进行判断,以便及时发现并解决问题。 总之,getsockoptsetsockopt函数是网络编程中必不可少的函数。它们用于设置和获取套接字的选项值,以便我们能够更加精细地控制网络通信的行为,从而提高网络通信效率和质量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值