当前位置:网站首页>套接字选项
套接字选项
2022-08-01 07:18:00 【oldmao_2000】
文章目录
WinSock提供了一些获取和设置套接口选项的函数。获取选项可以得到套接口相关的一些参数、操作方式等;设置选项能够改变套接口的参数、控制底层协议的行为等。本章主要介绍:getsockopt/setsockopt、WSAIoctl和ioctlsocket,并对这些函数常用的设置选项进行介绍。
setsockopt
getsockopt/setsockopt分别用于获取和设置套接字的选项,这里主要以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
失败,返回SOCKET_ERROR
注意:
1.setsockopt一般应在bind的操作后调用,否则setsockopt即使设置也不会检查TCP/IP选项,直到调用bind后,才会检查TCP/IP选项,这种情况下,setsockopt只会返回执行成功。
2.打开的句柄调用setsockopt后,再调用sendto,则相当于调用bind。
3.选项的获取或设置需要考虑调用顺序,例如未报错时调用获取SO_ERROR则不会获得错误信息。
IPPROTO_IP
https://docs.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options
只写:
IP_ADD_MEMBERSHIP:加入多播组
IP_DROP_MEMBERSHIP:离开多播组
可读可写
IP_HDRINCL:用于表示是否使用自定义IP头,只支持原始套接字
IP_OPTIONS:设置IP包头中optional字段中的数据。
IP_TOS:设置IP包头中TOS字段中的数据。
IP_TTL:设置IP包头中TTL字段中的数据。
IP_DONTFRAGMENT:设置是否忽略MTU的限制,不分片,只支持UDP、ICMP。启用该选项后,发送数据大于本地接口的MTU会失败,错误码为:WSAEMSGSIZE。
IPPROTO_TCP
TCP_NODELAY:设置是否使用Nagle算法,即是否缓冲区只要有数据,不等待,立即发送。在实施通信应用用应设置为立即发送减少延迟。
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_MAX_MSG_SIZE:得到一次可以发送的最大数据报的大小,只能用于数据报套接口。
可读可写
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阻塞调用时等待时间。
ioctlsocket
ioctlsocket命令和下面要讲的WSAIoctl类似,前者主要是基于Winsock 1.0版本,兼容性较好;而后者基于Winsock 2.0版本,功能更加强大,支持的选项更多。
https://docs.microsoft.com/zh-cn/windows/win32/api/winsock/nf-winsock-ioctlsocket
int ioctlsocket(
[in] SOCKET s,
[in] long cmd,
[in, out] u_long *argp
);
参数①
Socket句柄
参数②
操作码/命令
1.FIONBIO:这个命令将socket置于非阻塞状态。在重叠IO等通信模式下,只要执行涉及非阻塞命令的函数,对应Socket就会自动进入非阻塞状态,不需要额外调用FIONBIO进行设置。
2.FIONREAD:返回指定Socket上可以读取的字节数。也可直接调用recv直接收取对应数据。
3.SIOCATMARK:返回Socket是否有OOB数据待读取,该命令只适用于设置了SO_OOBINLINE的SOCK_STREAM类型Socket。
参数③
操作码要设置的值
返回值
成功,返回0;
失败,返回SOCKET_ERROR。
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
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地址是否有变化。可在回调函数中写入具体处理变化的代码。
10.
参数③
操作码输入缓存的指针
参数④
参数③的大小
参数⑤
操作码输出缓存的指针
参数⑥
参数⑤的大小
参数⑦
实际返回值大小
参数⑧
异步模式下的重叠结构体
参数⑨
要执行的回调函数,定义方式如下:
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;
}
边栏推荐
- VSCode插件推荐(Rust环境)
- 请问用flinksql写入数据到clickhouse需要引入什么依赖吗?
- 【ASWC Arxml结构分解】-7-Explicit(显式)和Implicit(隐式) Sender-Receiver communication描述差异
- Create, modify and delete tables
- 根据指定区域内容生成图片并进行分享总结
- 我三本学历,五面阿里,被面试官“供”着出来了,拿了33*15的Offer
- Offer brush questions - 1
- pytest接口自动化测试框架 | 跳过测试类
- LabVIEW中局部变量和全局变量的分配
- How to generate and configure public key certificate in Alipay
猜你喜欢

【HDLBits 刷题】Circuits(1)Combinational Logic

Introduction to the basic principles, implementation and problem solving of crawler

NIO编程

微信小程序请求封装

插入排序—直接插入排序和希尔排序

七夕来袭——属于程序员的浪漫

How to generate and configure public key certificate in Alipay

电磁兼容简明教程(6)测试项目

MVVM项目开发(商品管理系统一)

Practical training Navicat Chinese and English mode switching
随机推荐
Data organization -- singly linked list of the linear table
LabVIEW RT中的用户界面更新速度
关于App不同方式更新的测试点归纳
配置我的kitty
Golang: go static file processing
sum of special numbers
Srping中bean的生命周期
Dart 异常详解
Json对象和Json字符串的区别
「面经分享」西北大学 | 字节 生活服务 | 一面二面三面 HR 面
Vim简介
GO错误处理方式
LeetCode240+312+394
电磁兼容简明教程(6)测试项目
Go 支持 OOP: 用 struct 代替 class
问下 mysql向pg同步多个表的话 有什么好的方案吗?
app 自动化 打开app (二)
选择排序—直接选择排序和堆排序
三维坐标系距离
Fist game copyright-free music download, League of Legends copyright-free music, can be used for video creation, live broadcast