2009-12-23 132 views
19

我正在使用POSIX C++程序的Windows端口。在Win64下將SOCKET強制轉換爲int是否安全?

問題是像accept()或bind()這樣的標準POSIX函數期望'int'作爲第一個參數,而其WinSock對應物使用'SOCKET'。
當32位編譯一切都很好,因爲兩者都是32位的,但Win64的SOCKET下是64位和INT保持32位,併產生大量的編譯器警告的是這樣的:

warning C4244: '=' : conversion from 'SOCKET' to 'int', possible loss of data

我試着通過使用typedef來解決問題:


#ifdef _WIN32 
typedef SOCKET sock_t; 
#else 
typedef int sock_t; 
#endif 

並在適當的位置用sock_t替換int。

這很好,直到我到達調用OpenSSL API的代碼的一部分。
事實證明,即使在Win64上,OpenSSL也使用套接字的套接字。這似乎真的很奇怪,於是我開始尋找答案,但我發現的唯一的事情是舊的文章,其refered的評論e_os.h OpenSSL的開發郵件列表:


/* 
* Even though sizeof(SOCKET) is 8, it's safe to cast it to int, because 
* the value constitutes an index in per-process table of limited size 
* and not a real pointer. 
*/ 

所以我的問題是:
將SOCKET強制轉換爲int是否真的很安全?

我希望看到一些證明SOCKET的值不能大於2^32的文檔。

在此先感謝!
Ryck

+0

+1:我有同樣的問題**會員** ... – paercebal 2010-05-26 13:22:28

回答

10

post似乎由在MSDN上重複上kernel objects的信息:

內核對象句柄是特定處理。也就是說,一個進程必須創建該對象或打開一個現有對象來獲得內核對象句柄。內核句柄的每進程限制是2^24。

該線程繼續引用Windows Internals by Russinovich and Solomon作爲高位爲零的源。

+0

感謝皮特! 這正是我所期待的。 以下是Mark Russinovich的博客上的相關文章: http://blogs.technet.com/markrussinovich/archive/2009/09/29/3283844.aspx – Ryck 2009-12-23 17:49:45

+0

+1爲多個鏈接 – paercebal 2010-05-26 13:23:01

+1

這是各種錯誤。首先,2^24內核句柄的限制並不意味着句柄將具有範圍[0,2^24-1]中的值。其次,內核句柄的數量是隨時可能更改的內部實現細節(因此標題爲「Windows _Internals_」)。 – 2014-10-21 16:14:46

0
/* 
* Even though sizeof(SOCKET) is 8, it's safe to cast it to int, because 
* the value constitutes an index in per-process table of limited size 
* and not a real pointer. 
*/ 

這一評論是正確的。 SOCKET = Windows NT系列上的文件句柄。我從來沒有見過9x系列64位,所以應該沒有什麼可擔心的。

3

這個問題的簡單答案是否定的。看一下MSDN上的SOCKET值的描述:

除了值INVALID_SOCKET不是有效的套接字之外,Windows套接字句柄沒有任何限制。套接字句柄可以採用0到INVALID_SOCKET-1範圍內的任何值。

所以很明顯,該API允許在範圍[0,2^64的所有值 - 在64位的Windows 1)。如果API返回的值大於2^32 - 1,則將其分配給int會導致句柄截斷。另請參見socket()函數返回值的描述[2]:

如果沒有錯誤發生,套接字將返回一個描述符來引用新套接字。

請注意,它最重要的是不承諾返回一個內核句柄。這使得關於內核句柄可能值的討論變得模糊。在寫這篇文章的時候,socket()函數確實返回一個內核句柄(或者與內核句柄不可區分的內核句柄)[3],而內核句柄實際上僅限於32位[4] 。但請記住,微軟明天可以在不破壞接口合同的情況下改變這些事情。但是,由於無疑有大量的應用程序依賴於這些特定的實現細節(更重要的是,OpenSSL也是如此),所以微軟可能會考慮重做任何重大更改。所以繼續並將SOCKET投射到一個int。請記住,這是一種固有的危險,不好的做法,而且從權宜之計的角度來看,這種做法永遠不合理。

  1. http://msdn.microsoft.com/en-us/library/windows/desktop/ms740516(v=vs.85).aspx
  2. http://msdn.microsoft.com/en-us/library/windows/desktop/ms740506(v=vs.85).aspx
  3. http://msdn.microsoft.com/en-us/library/windows/desktop/ms742295(v=vs.85).aspx
  4. http://msdn.microsoft.com/en-us/library/windows/desktop/aa384267(v=vs.85).aspx

編輯(2018年1月29日)

由於這個話題似乎仍有些興趣,值得指出的是我T公司很容易編寫C++ 11便攜式插座的代碼,而不訴諸可疑的類型轉換:

using socket_t = decltype(socket(0, 0, 0)); 

socket_t s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
相關問題