Windows上使用MFC的DNS-SD
DNS-SD on Windows using MFC
我有一个使用MFC构建的应用程序,我需要添加Bonjour/Zeroconf服务发现。我有一点麻烦弄清楚如何最好地做到这一点,但我已经决定使用mDNSresponder源代码中提供的DLL存根,并将我的应用程序链接到由它生成的静态库(反过来使用系统dssd . DLL)。
然而,我仍然有问题,因为回调似乎并不总是被调用,所以我的设备发现停滞。让我困惑的是,在OSX下,使用OSX dns-sd终端服务,在Windows下使用dns-sd命令行服务,这一切都工作得很好。在此基础上,我排除了客户端服务是问题所在,并试图找出我的Windows代码出了什么问题。
我基本上调用DNSBrowseService(),然后在那个回调调用dnsservicerresolve(),然后最后调用DNSServiceGetAddrInfo()来获取设备的IP地址,这样我就可以连接到它。
所有这些调用都是基于像这样使用WSAAsyncSelect:
DNSServiceErrorType err = DNSServiceResolve(&client,kDNSServiceFlagsWakeOnResolve,
interfaceIndex,
serviceName,
regtype,
replyDomain,
ResolveInstance,
context);
if(err == 0)
{
err = WSAAsyncSelect((SOCKET) DNSServiceRefSockFD(client), p->m_hWnd, MESSAGE_HANDLE_MDNS_EVENT, FD_READ|FD_CLOSE);
}
但有时回调只是从来没有被调用,即使服务在那里,使用命令行将确认。
我完全被难住了,为什么这不是100%可靠,但如果我从命令行使用相同的DLL。我唯一可能的解释是,dnsservicerresolve函数试图在WSAAsyncSelect为套接字注册处理消息之前调用回调函数,但我看不到任何方法。
我花了很长时间在这上面,现在完全没有主意了。任何建议都是受欢迎的,即使他们是"这是一个非常愚蠢的方法,你为什么不做X, Y, Z"。
我调用DNSServiceBrowse
,使用"共享连接"(参见dns_sd.h
获取文档),如下所示:
DNSServiceCreateConnection(&ServiceRef);
// Need to copy the main ref to another variable.
DNSServiceRef BrowseServiceRef = ServiceRef;
DNSServiceBrowse(&BrowseServiceRef, // Receives reference to Bonjour browser object.
kDNSServiceFlagsShareConnection, // Indicate it's a shared connection.
kDNSServiceInterfaceIndexAny, // Browse on all network interfaces.
"_servicename._tcp", // Browse for service types.
NULL, // Browse on the default domain (e.g. local.).
BrowserCallBack, // Callback function when Bonjour events occur.
this); // Callback context.
这是在一个名为ServiceDiscovery
的线程类的主run
方法中。ServiceRef
是ServiceDiscovery
的成员。
紧接着上面的代码,我有一个像这样的主事件循环:
while (true)
{
err = DNSServiceProcessResult(ServiceRef);
if (err != kDNSServiceErr_NoError)
{
DNSServiceRefDeallocate(BrowseServiceRef);
DNSServiceRefDeallocate(ServiceRef);
ServiceRef = nullptr;
}
}
然后,在BrowserCallback
中,您必须设置解析请求:
void DNSSD_API ServiceDiscovery::BrowserCallBack(DNSServiceRef inServiceRef,
DNSServiceFlags inFlags,
uint32_t inIFI,
DNSServiceErrorType inError,
const char* inName,
const char* inType,
const char* inDomain,
void* inContext)
{
(void) inServiceRef; // Unused
ServiceDiscovery* sd = (ServiceDiscovery*)inContext;
...
// Pass a copy of the main DNSServiceRef (just a pointer). We don't
// hang to the local copy since it's passed in the resolve callback,
// where we deallocate it.
DNSServiceRef resolveServiceRef = sd->ServiceRef;
DNSServiceErrorType err =
DNSServiceResolve(&resolveServiceRef,
kDNSServiceFlagsShareConnection, // Indicate it's a shared connection.
inIFI,
inName,
inType,
inDomain,
ResolveCallBack,
sd);
然后在ResolveCallback
你应该有你需要的一切。
// Callback for Bonjour resolve events.
void DNSSD_API ServiceDiscovery::ResolveCallBack(DNSServiceRef inServiceRef,
DNSServiceFlags inFlags,
uint32_t inIFI,
DNSServiceErrorType inError,
const char* fullname,
const char* hosttarget,
uint16_t port, /* In network byte order */
uint16_t txtLen,
const unsigned char* txtRecord,
void* inContext)
{
ServiceDiscovery* sd = (ServiceDiscovery*)inContext;
assert(sd);
// Save off the connection info, get TXT records, etc.
...
// Deallocate the DNSServiceRef.
DNSServiceRefDeallocate(inServiceRef);
}
hosttarget
和port
包含您的连接信息,任何文本记录都可以使用DNS-SD API(例如TXTRecordGetCount
和TXTRecordGetItemAtIndex
)获得。
对于共享连接引用,当您使用完它们时,您必须基于(或从)父引用重新分配它们。我认为DNS-SD API做一些引用计数(和父/子关系)当你传递一个共享引用的副本到他们的函数之一。同样,请参阅文档了解详细信息。
我一开始试着不使用共享连接,我只是传递ServiceRef
,导致它在回调中被覆盖,我的主循环变得混乱。我认为,如果不使用共享连接,则需要维护需要进一步处理的引用列表(并处理每个引用),然后在完成后销毁它们。共享连接方法似乎简单得多。
- C++ MFC Libraries in Travis CI
- phytec phyBOARD iMX-6在从闪存而不是SD卡运行qt5 opengles应用程序时表现不佳(FPS减半
- 从 bmp 文件数据创建 MFC CBitmap
- libcurl 和 DNS ttl 中的内部连接管理
- 如何在 MFC 中显示文件的所有行
- 在不使用系统的情况下从C++应用程序格式化 Linux 中的 SD 卡
- 目录删除 MFC 的问题
- MFC:如何设置CEdit框的焦点?
- MFC 中的抗锯齿
- 双击更改 mfc 中列表控件中的行的颜色
- C++MFC编辑框处理双击
- C++ MFC CObject 派生类摘要?
- 如何在 MFC 对话框中使用 OnDraw
- 在 1 个服务器 n 客户端套接字 C++ MFC 应用程序中更新数据的客户端
- MFC:你能在CDateTimeCtrl中改变自旋的加速度吗?
- MFC:我们如何轻松地从CTreeCtrl切换到CTreeView?
- __int64 CString 返回错误的值 - C++ MFC
- 如何在MFC中的静态文本控件上插入图标?
- 使用 MFC 的表/网格
- Windows上使用MFC的DNS-SD