前言
筆者在將socket通信的自定義類從Linux移植到Windows時遇到一些問題,整理下來希望幫助到需要的人,同時也加深自己的理解。
差異
頭文件
#ifdef _WIN32
#include <ws2tcpip.h>
#define inet_pton InetPton
#define SHUT_RDWR SD_BOTH
#define MSG_NOSIGNAL 0
#else
#include <netinet/in.h>
#endif
Windows使用頭文件ws2tcpip.h
,Linux則是netinet/in.h
,舊版Windows不提供標準函數inet_pton
,但是有InetPton
,在這里用宏替換做了適配。另外Windows缺少的宏定義也做了簡單適配。
fd類型
Linux:int
Windows:SOCKET
,底層是UINT_PTR
類型,無效值INVALID_SOCKET
,定義為(SOCKET)(~0)
。
這里的適配代碼:
class TcpClientIO : public SocketIO
{
public:
#ifdef _WIN32using socket_t = SOCKET;
#elseusing socket_t = int;
#endifTcpClientIO();virtual ~TcpClientIO();private:socket_t sockFd_{static_cast<socket_t>(-1)};
};
static_cast<socket_t>(-1)
和(SOCKET)(~0)
結果應該是一致的。
send / recv
函數原型略微有差異。
Linux:ssize_t send (int __fd, const void *__buf, size_t __n, int __flags);
Windows:WINSOCK_API_LINKAGE int WSAAPI send(SOCKET s,const char *buf,int len,int flags);
初始化
適用Windows socket之前需要調用WSAStartup
初始化,Linux不需要。反初始化同樣(我實現的類沒有做這步,待完善)
TcpClientIO::TcpClientIO()
{
#if _WIN32std::lock_guard<std::mutex> lock(winsockMutex_);if (!winsockInitialized_) {WSADATA wsaData;WSAStartup(MAKEWORD(2,2), &wsaData);winsockInitialized_ = true;}
#endif...
}
用一個靜態成員變量記錄是否執行過初始化。
反初始化調用cleanupWinsock();
在整個程序結束時調用(并非在析構函數中調用)。
關閉fd
另一個容易被忽略的差異是關閉fd的接口。Windows使用closeSocket
而Linux使用close
。可以在Linux中定義#define closesocket close
,統一調用closesocket
.
庫包含
Windows中需要動態鏈接ws2_32.dll
,或者靜態鏈接#pragma comment(lib, "ws2_32.lib")
錯誤處理
Windows使用WSAGetLastError()
獲取錯誤信息,Linux可以用errno
。
當前的類實現并不是很完善,只滿足基礎需求。作為初學者,歡迎討論和批評指正。