setsockopt 子例程

用途

设置插座选项。

标准 C 库 (libc.a)

语法

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/atmsock.h> /*Needed for SOCK_CONN_DGRAM socket type 
only*/
int setsockopt
(Socket, Level, OptionName, OptionValue, OptionLength)
int  Socket,  Level,  OptionName;
const void * OptionValue;
socklen_t  OptionLength;

描述

setsockopt 子例程设置与套接字关联的选项。 选项可以存在于多个协议级别。 这些选项始终存在于最上层的套接字级别。

setsockopt 子例程为应用程序提供控制套接字通信的方法。 应用程序可以使用 setsockopt 子例程在协议级别启用调试,分配缓冲区空间,控制超时或允许套接字数据广播。 /usr/include/sys/socket.h 文件定义可用于 setsockopt 子例程的所有选项。

设置套接字选项时,请指定选项所在的协议级别以及选项的名称。

使用参数 OptionValueOptionLength 来访问 setsockopt 子例程的选项值。 这些参数标识在其中返回所请求选项的值的缓冲区。

包含 setsockopt 子例程的所有应用程序都必须在 _BSD 宏设置为特定值的情况下进行编译。 可接受的值为 43 和 44。 此外,所有套接字应用程序都必须包含 BSD libbsd.a 库。

参数

描述
套接字 指定唯一套接字名称。
级别 指定选项所在的协议级别。 要在以下位置设置选项:
套接字级别
Level 参数指定为 SOL_SOCKET
其他级别
为控制选项的协议提供相应的协议号。 例如,要指示某个选项将由 TCP 协议解释,请将 Level 参数设置为 TCP 的协议号,如 netinet/in.h 文件中所定义。 同样,要指示某个选项将由 ATM 协议解释,请将 Level 参数设置为 NDDPROTO_ATM ,如 sys/atmsock.h中所定义。
OptionName 指定要设置的选项。 OptionName 参数和任何指定的选项将以未解释的方式传递到相应的协议模块以进行解释。 sys/socket.h 文件定义套接字协议级别选项。 netinet/tcp.h 文件定义 TCP 协议级别选项。 可以启用或禁用套接字级别选项; 它们以切换方式运行。

以下列表定义了在 sys/socket.h 文件中找到的套接字协议级别选项:

SO_DEBUG
打开调试信息的记录。 此选项在底层协议模块中启用或禁用调试。 在命令级别通过下列其中一种方式设置此选项:
  • 使用 sodebug 命令,对现有套接字打开或关闭此选项。
  • inetd.conf 中的服务的 wait/nowait 字段中指定 |DEBUG[=level] ,以便为特定服务开启此选项。
  • sodebug_env 参数设置为 no,并在流程环境中指定 SODEBUG=level 。 这将对进程创建的所有后续套接字打开或关闭此选项。
级别 的值可以是 minnormaldetail
SO_REUSEADDR
指定用于验证 bind 子例程提供的地址的规则应允许复用本地端口。

SO_REUSEADDR 允许应用程序在设置了 SO_REUSEADDR 的情况下显式拒绝后续 bind 子例程到套接字的端口/地址。 这允许应用程序阻止其他应用程序与 bind 子例程绑定。

SO_REUSEPORT
指定在验证 bind 子例程提供的地址时使用的规则应允许复用本地端口/地址组合。 端口/地址组合的每个绑定都必须指定 SO_REUSEPORT 套接字选项
反向校验和
在协议层中启用性能增强功能。 如果协议支持此选项,那么启用将导致协议延迟校验和验证,直到将用户的数据移入用户的缓冲区 (在 recvrecvfromreadrecvmsg 线程上)。 如果发生校验和错误,这可能会导致应用程序在没有可用数据时被唤醒。 在此情况下,将返回 EAGAIN。 设置此选项的应用程序必须处理从接收调用返回的 EAGAIN 错误代码。
保持活动
通过在已连接的套接字上启用或禁用 ACK 消息的定期传输来监视连接的活动。 可以使用 TCP/IP no 命令指定空闲时间间隔。 "了解套接字类型和协议" Communications Programming Concepts中讨论了中断的连接。
OptionName
请勿转发
不对外发消息应用路由。 指示外发消息应绕过标准路由工具。 而是根据目的地址的网络部分将它们定向到相应的网络接口。
SO_BROADCAST
允许发送广播消息。
SO_LINGER
如果存在数据,那么在 close 子例程上进行徘徊。 此选项控制当套接字存在未发送的消息队列,并且进程在套接字上执行 close 子例程时所执行的操作。

如果设置了 SO_LINGER ,那么系统将在 close 子例程期间阻塞进程,直到它可以传输数据或直到时间到期为止。 如果未指定 SO_LINGER 并且发出了 close 子例程,那么系统将以允许进程尽快继续的方式处理调用。

sys/socket.h 文件定义 linger 结构,该结构包含用于指定 linger 时间间隔的 l_linger 成员。 如果 linger 时间设置为除 0 以外的任何值,那么系统将尝试发送在套接字上排队的任何消息。 l_linger 成员可设置为的最大值为 65535。 如果应用程序通过导出 XPG_SUS_ENV 环境变量来请求符合 SPEC1170 的行为,那么 linger 时间为 n 秒; 否则, linger 时间为 n/100 秒 (记号) ,其中 nl_linger 成员的值。

SO_OOBINLINE
接收到频带外数据 (标记为紧急的数据)。
SO_SNDBUF
设置发送缓冲区大小。
接收缓冲区
设置接收缓冲区大小。
SO_SNDLOWAT
设置发送低水位标记。
接收低电平
设置接收低水位标记。
SO_SNDTIMEO
设置使用 socket 调用的发送类型函数(如 sendwrite 子程序)在完成之前被阻塞的最长时间。 SO_SNDTIMEO 选项要求使用 TIMEVAL 结构。 TIMEVAL 结构包含秒数和微秒数。 可以微秒为单位指定 TIMEVAL 值。 不过,用于实现该功能的内部 TCP/IP 定时器的粒度为 10 毫秒。 如果超时值设置为小于 10 毫秒,其结果与未设置超时值时的行为相同。
SO_RCVTIMEO
设置使用 socket 调用的接收类型函数(如 recvread 子程序)在完成之前的最长等待时间。 SO_RCVTIMEO 选项要求使用 TIMEVAL 结构。 TIMEVAL 结构包含秒数和微秒数。 可以微秒为单位指定 TIMEVAL 值。 不过,用于实现该功能的内部 TCP/IP 定时器的粒度为 10 毫秒。 如果超时值设置为小于 10 毫秒,其结果与未设置超时值时的行为相同。
SO_ERROR
设置错误状态的检索和清除。
SO_TYPE
设置套接字类型的检索。
OptionName

以下列表定义了在 netinet/tcp.h 文件中找到的 TCP 协议级别选项:

TCP_CWND_IF
在避免拥塞期间增加 TCP 拥塞窗口 (cwnd) 的因子。 该值必须在 0-100 范围内 (0 表示禁用)。 必须启用 tcp_cwnd_modified 网络可调参数选项。
TCP_CWND_DF
在避免拥塞期间降低 TCP cwnd 的因子。 该值必须在 0-100 范围内 (0 表示禁用)。 必须启用 tcp_cwnd_modified 网络可调参数选项。
tcp_notenter_sstart
避免在重新传输超时后重新输入慢速启动,这可能会将 cwnd 重置为初始窗口大小,而不是当前慢速启动阈值 (ss_threshold) 值的大小或最大 cwnd (max cwnd/2) 的一半。 值为 1 (表示启用) 和 0 (表示禁用)。 必须启用 tcp_cwnd_modified 网络可调参数选项。
tcp_ noreduce_cwnd_in_frxmt
在快速重新传输短语时不减小 cwnd 大小。 值为 1 (表示启用) 和 0 (表示禁用)。 必须启用 tcp_cwnd_modified 网络可调参数选项。
tcp_ noreduce_cwnd_exit_frxmt
退出快速重新传输短语时不减小 cwnd 大小。 值为 1 (表示启用) 和 0 (表示禁用)。 必须启用 tcp_cwnd_modified 网络可调参数选项。
TCP_保持计数器
指定要发送以验证连接的最大保持活动包数。 此套接字选项值继承自父套接字。 缺省值为 8。
TCP_KEEPIDLE
指定连接上的空闲时间 (以秒计) ,在此时间之后, TCP 将发送保持活动包。 此套接字选项值继承自接受系统调用的父套接字。 缺省值为 7200 秒 (14400 半秒)。
TCP_保持连接时间值
指定保持活动包之间的时间间隔。 以秒为单位进行测量。 此套接字选项值继承自接受系统调用的父套接字。 缺省值为 75 秒 (150 半秒)。
tcp_nodelay
指定 TCP 是否应遵循 Nagle 算法来决定何时发送数据。 缺省情况下, TCP 将遵循 Nagle 算法。 要禁用此行为,应用程序可以启用 TCP_NODELAY 以强制 TCP 始终立即发送数据。 例如,当存在将 TCP 用于请求/响应的应用程序时,应使用 TCP_NODELAY
OptionName
TCP_RFC1323
在指定的 TCP 套接字上启用或禁用 RFC 1323 增强功能。 应用程序可能包含以下行以启用 RFC 1323:
int on=1;
setsockopt(s,IPPROTO_TCP,TCP_RFC1323,&on,
           sizeof(on));
TCP_STDURG
启用或禁用符合 RFC 1122 的紧急点处理。 缺省情况下, TCP 实现符合 4.2 BSD 操作系统的紧急指针行为,即,此选项缺省为 0。
TCP_NODELAYACK
指定 TCP 是否需要向发送方发送即时确认包。 如果未设置此选项,那么 TCP 将延迟发送确认包最多 200 毫秒。 这允许将应答与响应上的数据一起发送,并将系统开销降至最低。 设置此 TCP 选项可能会导致系统开销略有增加,但如果发送方正在等待接收方的应答,那么可能会导致网络传输的性能提高。

TCP 协议级别套接字选项从侦听套接字继承到新套接字。

以下列表定义了在 sys/atmsock.h 文件中找到的 ATM 协议级别选项:

ATM参数
设置所有 ATM 参数。 可以使用此套接字选项,而不使用下面描述的个别套接字选项。 它使用 sys/call_ie.h 文件中定义的 connect_ie 结构。
so_atm_aal_parm
设置 ATM AAL (适应层) 参数。 它使用 sys/call_ie.h 文件中定义的 aal_parm 结构。
So_ATM_TRAFFIC_DES
设置 ATM 流量描述符值。 它使用 sys/call_ie.h 文件中定义的 traffic 结构。
持卡人
设置 ATM 不记名功能。 它使用 sys/call_ie.h 文件中定义的 bearer 结构。
SO_ATM_BHLI
设置 ATM 宽带高层信息。 它使用 sys/call_ie.h 文件中定义的 bhli 结构。
SO_ATM_BLLI
设置 ATM 宽带低层信息。 它使用 sys/call_ie.h 文件中定义的 blli 结构。
ATM服务质量
设置 ATM 服务质量值。 它使用 sys/call_ie.h 文件中定义的 qos_parm 结构。
So_ATM_Transit_SEL
设置 ATM 传输选择器承运方。 它使用 sys/call_ie.h 文件中定义的 transit_sel 结构。
OptionName
自动柜员机接受
指示接受通过 ACCEPT 系统调用向应用程序指示的入局 ATM 呼叫。 这必须是要完全建立入局连接的问题。 这允许协商 ATM 参数。
so_atm_max_pend
设置在由于传输操作而向应用程序返回错误指示之前允许的未完成传输缓冲区数。 此选项仅对非尽力而为的虚拟电路类型有效。 OptionValue/OptionLength指向一个字节,其中包含该参数将被设置的值。

以下列表定义了在 netinet/sctp.h 文件中找到的 IPPROTO_TCP 协议级别选项:

sctp_peer_addr_params
启用或禁用关联的脉动信号,并修改关联的脉动信号间隔。 此选项使用 netinet/sctp.h 文件中定义的 sctp_paddrparams 结构。 对于 spp_address 字段, AIX® 现在仅支持通配符地址。 spp_flags 字段支持 SPP_HB_ENABLESPP_HB_DISABLESPP_HB_TIME_ISZERO 标志。 spp_hbinterval 字段可以设置为最小值 50 毫秒。
SCTP_MAXSEG
设置任何传出 SCTP DATA 块的最大大小。 如果消息大于指定的大小,那么消息将由 SCTP 分段为指定的大小。 它使用 netinet/sctp.h 文件中定义的 sctp_assoc_value 结构。
OptionValue OptionValue 参数采用 Int 参数。 要启用布尔选项,请将 OptionValue 参数设置为非零值。 要禁用某个选项,请将 OptionValue 参数设置为 0。

以下选项以相同方式启用和禁用:

  • SO_DEBUG
  • SO_REUSEADDR
  • 保持活动
  • 请勿转发
  • SO_BROADCAST
  • SO_OOBINLINE
  • SO_LINGER
  • TCP_RFC1323
OptionLength OptionLength 参数包含 OptionValue 参数指向的缓冲区大小。

其他协议级别的选项的格式和名称各不相同。

描述
IP_禁止分片 从现在开始为 IP 头中的每个包设置 DF 位。 为了检测路径 MTU 中的减少, UDP 应用程序使用 IP_DONTFRAG 选项。
IP_查找MTU 设置对此路径启用/禁用 PMTU 发现。 应该启用协议级别路径 MTU 发现,才能进行发现。
IP_PMTU年龄 设置 PMTU 的年龄。 指定会话的 PMT 缩减发现频率。 将其设置为 0 (零) 意味着无限存在期,将不会尝试 PMTU 减少发现。 这将替换先前设置的 PMTU 年龄。 新的 PMTU 有效期在当前设置的计时器到期后生效。 当前未使用此选项,因为 UDP 应用程序必须设置 IP_DONTFRAG 套接字以立即检测 PMTU 中的减少。
IP_TTL 在每个包的 IP 头中设置生存时间字段。 但是,对于原始套接字,将在发送消息时使用缺省 MAXTTL 值,而不考虑使用 setsockopt 子例程设置的值。
IP_HDR_INCL 此选项允许用户构建自己的 IP 头。 它指示完整的 IP 头包含在数据中,并且只能用于原始套接字。
IP_ADD_成员资格 连接多点广播组,如 ip_mreq 结构类型的 OptionValue 参数中所指定。
IP_DROP_成员资格 保留 ip_mreq 结构类型的 OptionValue 参数中指定的多点广播组。
ip_multicast_if 允许在接口上发送多点广播消息,如 ip_addr 结构类型的 OptionValue 参数中所指定。 INADDR_ANY (0x000000000) 的地址将除去多点广播选项中先前选择的接口。 如果未指定接口,那么将使用指向缺省路由的接口。
ip_multicast_loop 设置多点广播回送,确定是否将传输的消息传递到发送主机。 char 类型的 OptionValue 参数控制要开启或关闭的回送。
ip_multicast_ttl 设置多点广播包的生存时间 (TTL)。 char 类型的 OptionValue 参数设置从 0 到 255 的 TTL 值。
IP_block_source 将给定源中的数据阻塞到给定组。
IP_unblock_source 取消阻塞源 (以撤销 IP_BLOCK_SOURCE 操作)。
IP_ADD_SOURCE_成员资格 连接特定于源的多点广播组。 如果主机是组的成员,请接受来自源的数据; 否则,请加入组并接受来自给定源的数据。
IP_DROP_SOURCE_成员资格 保留特定于源的多点广播组。 从给定的多点广播组列表中删除源。 要删除给定组的所有源,请使用 IP_DROP_MEMBERSHIP 套接字选项。
描述
IPPROTO_IPV6 将 AF_INET6 套接字限制为仅 IPv6 通信。
选项类型:
int (布尔解释)
  允许用户设置单点广播 IPv6 包的传出中继段限制。
选项类型:
int(x)
选项值:
x <-1错误 EINVAL
x ==-1使用内核默认值
0 <= x <= 255 使用
x> = 256 错误 EINVAL
  允许用户设置多点广播 IPv6 包的传出中继段限制。
选项类型:
int(x)
选项值:
解释与 IPV6_UNICAST_HOPS (上面列出) 相同。
  允许用户指定用于传出多点广播包的接口。 如果指定为 0 ,那么系统将选择出局接口。
选项类型:
无符号整数 (要使用的接口的索引)
  如果将多点广播数据报发送到发送主机所属的组,那么 IP 层将回送该数据报的副本以进行本地传递 (如果该选项设置为 1)。 如果该选项设置为 0 ,那么不会回送副本。
选项类型:
unsigned int
  在指定的本地接口上连接多点广播组。 如果将接口索引指定为 0 ,那么内核将选择本地接口。
选项类型:
struct ipv6_mreq ,如 netinet/in.h 文件中所定义
  将多点广播组保留在指定接口上。
选项类型:
struct ipv6_mreq ,如 netinet/in.h 文件中所定义
  指定内核计算原始套接字的数据和 pseudo-IPv6 头的校验和。 内核将计算出局包的校验和以及验证该套接字上的入局包的校验和。 将废弃具有不正确校验和的入局包。 缺省情况下,此选项处于禁用状态。
选项类型:
整数
选项值:
必须存储校验和结果的用户数据中的偏移量。 这必须是一个积极的偶数值。 将值设置为-1将禁用该选项。
  使入局 IPv6 包的目标 IPv6 地址和到达接口索引作为 UDP 和原始套接字上的辅助数据接收。
选项类型:
int (布尔解释)
  使入局 IPv6 包的中继段限制作为 UDP 和原始套接字上的辅助数据接收。
选项类型:
int (布尔解释)
  使入局 IPv6 包的流量类作为 UDP 和原始套接字上的辅助数据接收。
选项类型:
int (布尔解释)
  使入局 IPv6 包的路由头 (如果有) 作为 UDP 和原始套接字上的辅助数据接收。
选项类型:
int (布尔解释)
  使入局 IPv6 包的逐跳选项头 (如果有) 作为 UDP 和原始套接字上的辅助数据接收。
选项类型:
int (布尔解释)
  使入局 IPv6 包的目标选项头 (如果有) 作为 UDP 和原始套接字上的辅助数据接收。
选项类型:
int (布尔解释)
  设置要在此套接字上发送的所有 IPv6 包的源 IPv6 地址和出局接口索引。 可以通过执行常规 塞索克特 ( ipi6_addrin6addr_anyipi6_ifindex 为 0) 来清除此选项。
选项类型:
struct in6_pktinfonetinet/in.h 文件中定义。
  设置此套接字上传出 IPv6 数据报的下一个中继段。 可以通过执行长度为 0 的常规 setsockopt 来清除此选项。 请注意,在这种情况下,仍必须为选项值提供内存指针。
选项类型:
netinet/in.h 文件中定义的 struct sockaddr_in6
  设置此套接字上传出 IPv6 数据报的流量类。 要清除该选项,应用程序可指定-1为值。
选项类型:
int(x)
选项值:
x <-1错误 EINVAL
x ==-1使用内核默认值
0 <= x <= 255 使用
x> = 256 错误 EINVAL
  设置要用于此套接字上的传出 IPv6 数据报的路由头。 可以通过执行长度为 0 的常规 setsockopt 来清除此选项。 请注意,在这种情况下,仍必须为选项值提供内存指针。
选项类型:
netinet/ip6.h 文件中定义的 struct ip6_rthdr
  设置要用于此套接字上的传出 IPv6 数据报的逐跳选项头。 可以通过执行长度为 0 的常规 setsockopt 来清除此选项。 请注意,在这种情况下,仍必须为选项值提供内存指针。
选项类型:
struct ip6_hbhnetinet/ip6.h 文件中定义。
  设置要用于此套接字上的传出 IPv6 数据报的目标选项头。 此头将跟在路由头之后 (如果存在) ,并且在未指定路由头时也将使用此头。 可以通过执行长度为 0 的常规 setsockopt 来清除此选项。 请注意,在这种情况下,仍必须为选项值提供内存指针。
选项类型:
netinet/ip6.h 文件中定义的 struct ip6_dest
  设置要用于此套接字上的传出 IPv6 数据报的目标选项头。 此头将在路由头之前 (如果存在)。 如果未指定路由头,那么将以静默方式忽略此选项。 可以通过执行长度为 0 的常规 setsockopt 来清除此选项。 请注意,在这种情况下,仍必须为选项值提供内存指针。
选项类型:
netinet/ip6.h 文件中定义的 struct ip6_dest
  设置此选项以控制 IPv6 路径 MTU 发现。
选项类型:
整数
选项类型:
--1对单播目的地执行路径 MTU 发现,但不对组播destinations.0执行 始终执行路径 MTUdiscovery.1 始终禁用路径 MTU 发现,并以最小 MTU 发送包。
  设置此选项可防止此套接字上传出 IPv6 包的分段。 如果正在发送的包大于出局接口 MTU ,那么将废弃该包。
选项类型:
int (布尔解释)
  通过设置此选项来启用 IPV6_PATHMTU 辅助数据项的接收。
选项类型:
int (布尔解释)
  设置此套接字的地址选择首选项。
选项类型:
INT
选项值:
netinet/in.h 中定义的 IPV6_PREFER_SRC_* 标志的组合
  连接多点广播组,如 group_req 结构的 OptionValue 参数中所指定。 如果指定的接口索引为 0 ,那么内核将选择缺省接口。
选项类型:
struct group_req ,如 netinet/in.h 文件中所定义
  保留 group_req 结构的 OptionValue 参数中指定的多点广播组。
选项类型:
struct group_req ,如 netinet/in.h 文件中所定义
  将指定源中的数据阻塞到指定的多点广播组。
选项类型:
struct group_source_req ,如 netinet/in.h 文件中所定义
  将数据从指定的源取消阻塞到指定的多点广播组。 此选项用于撤销 MCAST_BLOCK_SOURCE 操作。
选项类型:
struct group_source_req ,如 netinet/in.h 文件中所定义
  连接特定于源的多点广播组。 如果主机已经是组的成员,请接受来自指定源的数据; 否则,请加入组并接受来自指定源的数据。
选项类型:
struct group_source_req ,如 netinet/in.h 文件中所定义
  保留特定于源的多点广播组。 从指定的多点广播组中保留指定的源。 要保留多点广播组的所有源,请使用 IPV6_LEAVE_GROUPMCAST_LEAVE_GROUP 套接字选项。
选项类型:
struct group_source_req ,如 netinet/in.h 文件中所定义
描述
IPPROTO_ICMPV6 允许用户按 ICMPV6 类型字段过滤 ICMPV6 消息。 要清除现有过滤器,请发出长度为零的 setsockopt 调用。
选项类型:
netinet/icmp6.h 文件中定义的 icmp6_filter 结构。
以下值 (在 /usr/include/netint/tcp.h 文件中定义) 由 setsockopt 子例程用于配置 dacinet 函数。
注: DACinet 工具仅在 CAPP/EAL4 + 配置的 AIX 系统中可用。
tcp.h:#define TCP_ACLFLUSH    0x21    /* clear all DACinet ACLs */
tcp.h:#define TCP_ACLCLEAR    0x22    /* clear DACinet ACL */
tcp.h:#define TCP_ACLADD      0x23    /* Add to DACinet ACL */
tcp.h:#define TCP_ACLDEL      0x24    /* Delete from DACinet ACL */
tcp.h:#define TCP_ACLLS       0x25    /* List DACinet ACL */
tcp.h:#define TCP_ACLBIND     0x26    /* Set port number for TCP_ACLLS */
tcp.h:#define TCP_ACLGID      0x01    /* ID being added to ACL is a GID */
tcp.h:#define TCP_ACLUID      0x02    /* ID being added to ACL is a GID */
tcp.h:#define TCP_ACLSUBNET   0x04    /* address being added to ACL is a subnet */
tcp.h:#define TCP_ACLDENY     0x08    /* this ACL entry is for denying access */

返回值

成功完成后,将返回值 0。

如果 setsockopt 子例程不成功,那么子例程处理程序将执行以下函数:

  • 向调用程序返回-1。
  • 将指示特定错误的错误代码移动到 errno 全局变量中。

错误代码

描述
EBADF Socket 参数无效。
Efault Address 参数不在用户地址空间的可写部分中。
EINVAL OptionValue 参数或 OptionLength 参数无效或套接字已关闭。
ENOBUFS 内存不足,无法用于内部数据结构。
ENOTSOCK Socket 参数引用文件,而不是套接字。
ENOPROTOOPT 选项未知。
EOPNOTSUPP 该选项不受套接字系列或套接字类型支持。
EPERM 用户应用程序无权获取或设置此套接字选项。 检查网络可调参数选项

示例

  • 要标记用于广播的套接字:
    int on=1;
    setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
  • 要开启 TCP_NODELAYACK 选项,请运行以下命令:
    int on=1;
    setsockopt(s, IPPROTO_TCP, TCP_NODELAYACK, &on, sizeof(on));