前言
笔者在将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 _WIN32
using socket_t = SOCKET;
#else
using socket_t = int;
#endif
TcpClientIO();
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 _WIN32
std::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。
当前的类实现并不是很完善,只满足基础需求。作为初学者,欢迎讨论和批评指正。
1181

被折叠的 条评论
为什么被折叠?



