套接字选项

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;

以上是关于套接字选项的主要内容,如果未能解决你的问题,请参考以下文章

套接字选项

Linux socket编程 套接字选项

socket选项总结(setsocketopt)

尝试连接到已经处理请求的套接字的传入连接会发生啥?

UNP-套接字选项

TCP/IP网络编程:09套接字的多种可选项