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

时间:2014-07-31 20:06:45

标签: c++ windows sockets winsock2

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

2 个答案:

答案 0 :(得分:11)

在POSIX文件中,描述符是整数值,而requires表示open返回的值“是当前未为该进程打开的最低文件描述符”。这条规则实际上似乎并不适用于socket,但我现在也没有任何不适用此规则的Unix系统。

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

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

如果您使用Process Explorer查看正在运行的进程并打开显示未命名的句柄和映射选项,您会看到即使是最简单的进程也会有很多打开处理。如果启用 Handle 列并使用它对列表进行排序,您还会看到最低句柄值为4,并且它们都是4的倍数。大多数(如果不是全部)倍数将分配4到4之间的最高数字。

虽然他没有完全解释原因,但Raymond Chen在他的Old New Thing博客上Why are kernel HANDLEs always a multiple of four?确实说保证处理是4的倍数:

  

不太知名的是内核HANDLE的底部两位总是为零;在   换句话说,它们的数值始终是4的倍数。请注意,这仅适用   到内核​​HANDLEs;它不适用于伪句柄或任何其他类型的句柄(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在Pushing the Limits of Windows: Handles上的博客讨论了一些关于如何在Windows上实现句柄的内部细节。不幸的是,它没有描述如何实际分配句柄值,但我想我可以推测一些细节。博客条目描述了“三级方案”。句柄用作每进程句柄表的索引,该表包含指向每进程句柄条目表的指针,该表又包含指向句柄的内核对象的指针。 Windows会根据需要增加这些表,并且可能会尝试通过在句柄关闭后重用句柄来节省内存。

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

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

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

答案 1 :(得分:4)

你可能想要的关于Winsock的更多信息:(这意味着你应该阅读并吸收所有这些; - )

http://www.tenouk.com/Winsock/Winsock2story.html

Jeremy是正确的,ID可以是文件HANDLE,窗口HANDLE,或者只是一个未使用的int值。在进行IO完成端口时,我已经看到了看起来像是错误的指针,所以它实际上可能会根据您正在使用的Windows网络的哪个部分而有所不同。 (Winsock,Winsock2等)