Zmq适配Win7 SP0 / Win XP/ Win 2k

1.目的

由于发布版本的libzmq使用了较多新的系统特性,导致在低版本windows平台上无法使用。
因此,需要对zmq源码进行修改以适配低版本的系统,如Win7 SP0,Win XP,Win2003等等。

2.Win7 SP0

#if defined ZMQ_HAVE_WINDOWS && defined WSA_FLAG_NO_HANDLE_INHERIT
    // if supported, create socket with WSA_FLAG_NO_HANDLE_INHERIT, such that
    // the race condition in making it non-inheritable later is avoided
    const fd_t s = WSASocket (domain_, type_, protocol_, NULL, 0,
                              WSA_FLAG_OVERLAPPED|WSA_FLAG_NO_HANDLE_INHERIT);
#else
    const fd_t s = socket (domain_, type_, protocol_);
#endif

zmq在高版本系统上为了通信安全考虑,使用了WSA_FLAG_NO_HANDLE_INHERIT标志,但是由于WSA_FLAG_NO_HANDLE_INHERIT这个标志是从 Windows 7 with SP1, Windows Server 2008 R2 with SP1开始支持的,因此在Win7 SP0系统上会出现socket连接无法初始化的问题。

解决方法:
方案1:取消WSA_FLAG_NO_HANDLE_INHERIT标志的使用
方案2:参考Win XP

3.Win XP

由于Windows XP系统与现代操作系统差别较大,系统库差异较大,因此,需要对项目进行较大的变更。

1. 选择VS对应版本的工程文件

​ 以VS2013为例 :libzmq-4.3.4\builds\deprecated-msvc\vs2013\libzmq.sln

2. 选择支持XP系统的工具集

Windows XP (v120_xp)

3. 项目文件变更
文件名 操作
src\channel.cpp 新增
src\endpoint.cpp 新增
src\ip_resolver.cpp 新增
src\peer.cpp 新增
src\raw_engine.cpp 新增
src\stream_connecter_base.cpp 新增
src\stream_engine_base.cpp 新增
src\stream_listener_base.cpp 新增
src\tweetnacl.c 新增
src\v3_1_encoder.cpp 新增
src\zmtp_engine.cpp 新增
src\stream_engine.cpp 删除
4. 预处理器定义

ZMQ_IOTHREAD_POLLER_USE_SELECT;
ZMQ_POLL_BASED_ON_SELECT;
ZMQ_HAVE_CURVE;
ZMQ_USE_TWEETNACL;

5. 代码兼容

1)ConditionVariable最低支持的客户端版本是Windows Vista,因此若支持C++11中的std::condition_variable_any,则可以使用ZMQ_USE_CV_IMPL_STL11定义规避此问题。否则,需要使用第三方库或者利用事件(event)或信号量(semaphore)来实现条件变量。

#include "windows.hpp"

namespace zmq
{
class condition_variable_t
{
  public:
    inline condition_variable_t () { InitializeConditionVariable (&_cv); }

    inline int wait (mutex_t *mutex_, int timeout_)
    {
        int rc = SleepConditionVariableCS (&_cv, mutex_->get_cs (), timeout_);

        if (rc != 0)
            return 0;

        rc = GetLastError ();

        if (rc != ERROR_TIMEOUT)
            win_assert (rc);

        errno = EAGAIN;
        return -1;
    }

    inline void broadcast () { WakeAllConditionVariable (&_cv); }

  private:
    CONDITION_VARIABLE _cv;

    ZMQ_NON_COPYABLE_NOR_MOVABLE (condition_variable_t)
};
}

2)if_indextoname最低支持的客户端版本是Windows Vista。因此,需要在XP上重新实现这个方法。

 #include 
 
static PCHAR WINAPI if_indextoname_custom (__in NET_IFINDEX InterfaceIndex,
                                         __out_ecount (IF_NAMESIZE)
                                           PCHAR InterfaceName)
{
    typedef PCHAR (WINAPI * fn_if_indextoname) (NET_IFINDEX InterfaceIndex,
                                                PCHAR InterfaceName);
    PCHAR ret = NULL;
    if (HMODULE hDll = LoadLibraryA ("Iphlpapi.dll")) {
        fn_if_indextoname _if_indextoname =
          (fn_if_indextoname) GetProcAddress (hDll, "if_indextoname");
        if (_if_indextoname)
            ret = _if_indextoname (InterfaceIndex, InterfaceName);
        FreeLibrary (hDll);
    }
    return ret;
}

4.Win2000

由于windows2000的版本过低,因此只能使用较低版本的开发工具VS2005。

1. 选择适当版本的VS工程文件

libzmq-4.3.4\builds\deprecated-msvc\vs2008\libzmq.sln

2. 工程文件变更
解决方案:
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
↓
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005

工程文件:
3. 步骤3/4与XP相同

省略

4. 代码兼容

1)ConditionVariable
与XP相同,省略
2)GetAdaptersAddresses
由于resolve_nic_name函数业务相关性较低,因此采用NOP方式规避。

    if (!resolved && _options.allow_nic_name ()) {
        //  Try to resolve the string as a NIC name.
        const int rc = -1; // resolve_nic_name (ip_addr_, addr_str);
		errno = ENODEV;
        //......
    }

3)getaddrinfo
虽然windows2000 原生不支持getaddrinfo函数,但是可以通过windows 2000 ipv6 预览版扩展系统功能,以支持getaddrinfo。

#include 
#include   //在后包含
5. 安装windows 2000 ipv6 预览版

你可能感兴趣的:(windows)