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 avoidedconst fd_t s = WSASocket (domain_, type_, protocol_, NULL, 0,WSA_FLAG_OVERLAPPED|WSA_FLAG_NO_HANDLE_INHERIT);
#elseconst 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 <netioapi.h>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工程文件:
<VisualStudioProject ProjectType="Visual C++" Version="9,00"
或者
<VisualStudioProject ProjectType="Visual C++" Version="9.00"
↓
<VisualStudioProject ProjectType="Visual C++" Version="8.00"編碼:
UTF-8 BOM → ANSI換行符:
LF → CRLF
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 <ws2tcpip.h>
#include <wspiapi.h> //在<ws2tcpip.h>后包含<wspiapi.h>