socket通信在Windows和Linux上的区别

前言

笔者在将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

当前的类实现并不是很完善,只满足基础需求。作为初学者,欢迎讨论和批评指正。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值