由于发布版本的libzmq使用了较多新的系统特性,导致在低版本windows平台上无法使用。
因此,需要对zmq源码进行修改以适配低版本的系统,如Win7 SP0,Win XP,Win2003等等。
#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
由于Windows XP系统与现代操作系统差别较大,系统库差异较大,因此,需要对项目进行较大的变更。
以VS2013为例 :libzmq-4.3.4\builds\deprecated-msvc\vs2013\libzmq.sln
Windows XP (v120_xp)
文件名 | 操作 |
---|---|
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 | 删除 |
ZMQ_IOTHREAD_POLLER_USE_SELECT;
ZMQ_POLL_BASED_ON_SELECT;
ZMQ_HAVE_CURVE;
ZMQ_USE_TWEETNACL;
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;
}
由于windows2000的版本过低,因此只能使用较低版本的开发工具VS2005。
libzmq-4.3.4\builds\deprecated-msvc\vs2008\libzmq.sln
解决方案:
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
↓
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
工程文件:
省略
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 //在后包含