套接字选项
Posted oldmao_2000
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了套接字选项相关的知识,希望对你有一定的参考价值。
文章目录
setsockopt
https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-setsockopt
int setsockopt(
[in] SOCKET s,
[in] int level,
[in] int optname,
[in] const char *optval,
[in] int optlen
);
参数①
需要设置Socket句柄
参数②
由于选项是层级结构,因此这里给出的命名是level,即选项所属的level(类别)
https://docs.microsoft.com/en-us/windows/win32/winsock/socket-options
常见的level有:
(画表)
IPPROTO_IP:IPv4协议选项
IPPROTO_IPV6:IPv6协议选项
IPPROTO_RM:可靠/稳定多播选项
IPPROTO_TCP:TCP选项
IPPROTO_UDP:UDP选项
NSPROTO_IPX:IPX选项
SOL_APPLETALK:AppleTalk选项
SOL_IRLMP:红外连接管理协议选项
SOL_SOCKET:套接字选项
设置选项使用的函数是:setsockopt;获取选项使用的函数是:getsockopt
有些选项是不可设置的,相当于只读的选项。
当然也有些选项是既可以设置又可以读取的。
参数③
要设置的选项名
参数④
要设置的选项值,使用指针的方式定义
有两类选项值:布尔值和非布尔值。对于布尔值的选项,可以设置一个非零的整型用于标记启用该选项,设置0用于标记关闭该选项。对于非布尔值的选项,需要将选项值对应的值或者结构体指针设置到参数④。
参数⑤
参数④的大小
返回值
成功,返回0
失败,返回错误码
注意:
1.setsockopt一般应在bind的操作后调用,否则setsockopt即使设置也不会检查TCP/IP选项,直到调用bind后,才会检查TCP/IP选项,这种情况下,setsockopt只会返回执行成功。
2.打开的句柄调用setsockopt后,再调用sendto,则相当于调用bind。
IPPROTO_IP
https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options
可读可写
IP_HDRINCL:用于表示是否使用自定义IP头
IP_OPTIONS:设置IP包头中optional字段中的数据。
IP_TOS:设置IP包头中TOS字段中的数据。
IP_TTL:设置IP包头中TTL字段中的数据。
IP_DONTFRAGMENT:设置是否忽略MTU的限制,不分片
IPPROTO_TCP
TCP_NODELAY:设置是否缓冲区只要有数据,不等待,立即发送。
SOL_SOCKET
https://docs.microsoft.com/en-us/windows/win32/winsock/sol-socket-socket-options
只读:
SO_ACCEPTCONN:用于查看套接字是否处于listen状态。
SO_CONNECT_TIME:用于查询客户端请求连接所经过的时间,以秒为单位。只支持TCP,通常用来判断等待时间过长的连接,并关闭之。
SO_PROTOCOL_INFO:用于查询底层协议信息,作用与WSAEnumProtocols类似
SO_ERROR:用于查询最后一次Socket上发生的错误码。
SO_TYPE:用于查询Socket的类型,例如:SOCK_STREAM、SOCK_DGRAM等
可读可写
SO_BROADCAST:用于查看或者设置socket是否可以发送广播数据,只能用于IPX、UDP,不可用于TCP。·
SO_CONDITIONAL_ACCEPT:用于设置服务器Socket是否自动Accept客户端的连接请求,默认是False,服务器会自动Accept客户端的连接请求(完成三次握手),设置为True后,需要应用程序调用WSAAccept(https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsaaccept)回调函数完成Accept客户端的连接请求。
SO_DONTLINGER:设置该选项可使得在关闭套接字(closesocket)后,套接字仍然保持打开状态,并将未发送完的数据继续发送完毕后关闭,只支持TCP。
SO_LINGER:接上一个选项,设置套接字保持打开的时间长度,单位为秒。
SO_REUSEADDR:用于将多个Socket绑定到相同IP地址和端口号
SO_EXCLUSIVEADDRUSE:用于设置防止多个Socket绑定到相同IP地址和端口号,该选项必须在bind前设置才有效。SO_EXCLUSIVEADDRUSE设置后SO_REUSEADDR无效。
SO_KEEPALIVE:设置后客户端会每隔1秒钟向服务器发送心跳数据,保持正常连接,最长可维持发送2小时的心跳数据,只支持TCP。
SO_OOBINLINE:设置该选项使得带外数据(OOB)作为带内数据一样处理,只支持打开OOB的TCP。
SO_RCVBUF:用于设置套接字接收数据缓冲区的大小,这个数据缓冲区是Socket自带用于存放接收数据的,不是Recv函数中指定的缓冲区。(加解释)
SO_SNDBUF:同上,但设置的是发送数据缓冲区的大小。
SO_RCVTIMEO:recv阻塞调用时等待时间,单位是毫秒,默认值为0,代表一直等待。
SO_SNDTIMEO:同上,但设置的是send阻塞调用时等待时间。
WSAIoctl
https://docs.microsoft.com/en-us/windows/win32/api/Winsock2/nf-winsock2-wsaioctl
int WSAAPI WSAIoctl(
[in] SOCKET s,
[in] DWORD dwIoControlCode,
[in] LPVOID lpvInBuffer,
[in] DWORD cbInBuffer,
[out] LPVOID lpvOutBuffer,
[in] DWORD cbOutBuffer,
[out] LPDWORD lpcbBytesReturned,
[in] LPWSAOVERLAPPED lpOverlapped,
[in] LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
参数①
Socket句柄
参数②
操作码/命令
https://docs.microsoft.com/en-us/windows/win32/winsock/winsock-ioctls
Unix IOCTL
1.FIONBIO:这个命令将socket置于非阻塞状态。在重叠IO等通信模式下,只要执行涉及非阻塞命令的函数,对应Socket就会自动进入非阻塞状态,不需要额外调用FIONBIO进行设置。
2.FIONREAD:返回指定Socket上可以读取的字节数。也可直接调用recv直接收取对应数据。
3.SIOCATMARK:返回Socket是否有OOB数据待读取,该命令只适用于设置了SO_OOBINLINE的SOCK_STREAM类型Socket。
Windows Sockets 2 IOCTL
1.SIO_ENABLE_CIRCULAR_QUEUEING:用于设置Socket缓冲区满后,是否用新数据替换缓冲队列的数据,仅支持UDP。
2.SIO_FLUSH,清空Socket发送缓冲区。
3.SIO_GET_EXTENSION_FUNCTION_POINTER,获取扩展函数指针地址,例如AcceptEx。
4.SIO_KEEPALIVE_VALS,和setsockopt函数的SO_KEEPALIVE选项有关系,这个命令可以设置一个TCP连接多长时间不活动就断开的时长,以及心跳数据的间隔。
5.SIO_RCVALL:设置Socket忽略端口号,接收发送到当前接口上的所有 IPv4 或 IPv6 数据包。该操作码需要管理员权限,套接字类型为SOCK_RAW
6.SIO_ROUTING_INTERFACE_QUERY:根据目标地址返回到达该目标地址的接口对应的IP地址。
7.SIO_ROUTING._INTERFACE_CHANGE:查询当前Socket绑定的网络接口对应IP地址是否发生变化。可在回调函数中写入具体处理变化的代码。
8.SIO_ADDRESS LIST_QUERY,可以查询当前计算机某个协议的所有接口。(看例子)
9.SIO_ADDRESS_LIST_CHANGE,可以查询本地某个协议IP地址是否有变化。可在回调函数中写入具体处理变化的代码。
参数③
操作码输入缓存的指针
参数④
参数③的大小
参数⑤
操作码输出缓存的指针
参数⑥
参数⑤的大小
参数⑦
实际返回值大小
参数⑧
异步模式下的重叠结构体
参数⑨
要执行的回调函数,定义方式如下:
void CALLBACK CompletionRoutine(
IN DWORD dwError,
IN DWORD cbTransferred,
IN LPWSAOVERLAPPED lpOverlapped,
IN DWORD dwFlags
);
返回值
成功,返回0;
失败,返回SOCKET_ERROR。
IO_ADDRESS LIST_QUERY使用实例:
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include<winsock2.h>
#include<stdio.h>
#pragma comment(lib, "ws2_32.lib")
int main()
WORD wVersionRequested = MAKEWORD(2, 2);//版本
WSADATA wsaDATA;
//打开网络库
if (WSAStartup(wVersionRequested, &wsaDATA) != 0)
printf("打开网络库失败!\\n");
return -1;
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);//创建Socket句柄
struct sockaddr_in si;
si.sin_family = AF_INET;
si.sin_port = htons(9527);//用htons宏将整型转为端口号的无符号整型
si.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
if (SOCKET_ERROR == bind(sock, (const struct sockaddr*)&si, sizeof(si)))
int err = WSAGetLastError();//取错误码
printf("服务器bind失败错误码为:%d\\n", err);
closesocket(sock);//释放
WSACleanup();//清理网络库
return 0;
printf("服务器端bind成功!\\n");
char Buf[0x1000] = 0 ;
DWORD dwBytes;
WSAOVERLAPPED ov = 0 ;
ov.hEvent = WSACreateEvent();
int ret = WSAIoctl(sock, SIO_ADDRESS_LIST_QUERY, NULL, 0, Buf, 0x1000, &dwBytes, NULL, NULL);
if (0 != ret)
int err = WSAGetLastError();//取错误码
printf("WSAIoctl失败错误码为:%d\\n", err);
closesocket(sock);//释放
WSACleanup();//清理网络库
return 0;
SOCKET_ADDRESS_LIST* slist = NULL;
SOCKADDR_IN* pAddrInet;
char* pAddrString;
slist = (SOCKET_ADDRESS_LIST*)Buf;
int num = slist->iAddressCount;
if (num > 0)
for (int i = 0; i < num; i++)
pAddrInet = ((SOCKADDR_IN*)slist->Address[i].lpSockaddr);
pAddrString = inet_ntoa(pAddrInet->sin_addr);
printf("IP%d:%s\\r\\n", i+1,pAddrString);
else
printf("没有读取到IP信息!/r/n/n");
closesocket(sock);//关闭Socket句柄
WSACleanup();//关闭网络库
return 0;
以上是关于套接字选项的主要内容,如果未能解决你的问题,请参考以下文章