为什么Windows上的套接字描述符得到这样的值?

Aen*_*nry 6 c++ sockets windows winsock2

无论如何,不​​确定这是否是正确的地方.
我正在用c ++编写一个简单的聊天,其中客户端获取套接字值作为开头的昵称.
在Linux套接字只是文件描述符,他们得到他们的3,4,5 ...跟随stdin,stdout,stderr.
但我注意到在Win上,第一个客户端套接字总是获得值192,而其他客户端套接字则相差20(几乎总是).
G
所以这就是我的问题,为什么套接字在win平台上获得这样的价值(我的是win7 x64)?小小的谷歌搜索没有帮助.
提前致谢

Ros*_*dge 11

在POSIX文件描述符是整数值,并要求open返回一个值"也就是最低的文件描述符目前没有开放这一进程".这条规则实际上似乎并不适用,socket但我现在也没有任何不适用此规则的Unix系统.

但是,Windows不使用POSIX套接字.它使用Windows套接字,可以通过与POSIX或原始BSD实现不兼容的方式自由定义.事实上,与Windows套接字存在许多不兼容的问题.大于预期的套接字值是一个相对较小的不兼容性,因为这些事情.

对于Windows套接字2,所有套接字"文件描述符"实际上都是Windows句柄.这意味着它们可以转换为HANDLE许多接受句柄作为参数的Windows API函数并在其中使用.它还意味着它们与Windows支持的一大堆不同类型的对象共享相同的值空间.文件,线程,注册表项,信号量等等.Windows在后台为进程分配了很多这些,Winsock DLL本身使用了相当多的数组,所以当你分配第一个套接字时,你的进程已经分配了大量的其他句柄.

如果使用Process Explorer查看正在运行的进程并打开Show Unnamed Handles and Mappings选项,您将看到即使是最简单的进程也有很多打开的句柄.如果启用Handle列并使用它对列表进行排序,您还会看到最低句柄值为4并且它们都是4的倍数.大多数(如果不是全部)4的倍数在4和最高之间列表上的号码将被分配.

虽然他没有解释为什么,Raymond Chen在他的Old New Thing博客中关于为什么内核HANDLE总是四个的倍数?确实说保证处理是4的倍数:

不太为人所知的是,内核HANDLE的底部两位始终为零; 换句话说,它们的数值始终是4的倍数.请注意,这仅适用于内核HANDLE; 它不适用于伪句柄或任何其他类型的句柄(USER>句柄,GDI句柄,多媒体句柄......)内核句柄是你可以传递给> CloseHandle函数的东西.

底部两位的可用性隐藏在ntdef.h头文件中: // // Low order two bits of a handle are ignored by the system and available // for use by application code as tag bits. The remaining bits are opaque // and used to store a serial number and table index. //

Mark Russinovich关于推动Windows限制的博客:Handles讨论了一些关于如何在Windows上实现句柄的内部细节.不幸的是,它没有描述如何实际分配句柄值,但我想我可以推测一些细节.博客条目描述了"三级方案".句柄用作每进程句柄表的索引,该表包含指向每进程句柄条目表的指针,该表又包含指向句柄的内核对象的指针.Windows会根据需要增长这些表,并且可能会尝试通过在句柄关闭后重用句柄来节省内存.

Process Explorer中的句柄列表差距很小也可能不是巧合.由于进程打开和关闭一直处理(通常由一些系统DLL在幕后完成),如果Windows没有积极地重用关闭的句柄,那么列表将更加稀疏.但是Windows首先重用最低的句柄吗?

测试显示它没有.我编写了一个程序,它创建了三个句柄,按顺序关闭第一个,第三个和第二个句柄,并在循环中重复所有这些句柄.如果Windows遵循POSIX规则,则每个循环迭代将以相同的顺序创建相同的句柄值,从最小到最大.但事实发生的是,它以与它们关闭的相反顺序创建了相同的句柄值.这表明Windows可能会在最近关闭的订单中重用句柄.我的猜测是它通过在句柄表中保留未分配句柄的链表来实现这一点.

那么为什么你的套接字值从192开始呢?可能是因为此时您的进程已经有47个打开的句柄.为什么你的插座相差20?可能是因为你在创建每个套接字之间创建了4个其他句柄.Winsock本身可能会在每次创建套接字时在幕后创建多个句柄.