DLL 中的非阻塞套接字(无窗口)
Posted
技术标签:
【中文标题】DLL 中的非阻塞套接字(无窗口)【英文标题】:Non blocking socket from within a DLL (no window) 【发布时间】:2009-11-24 14:05:04 【问题描述】:我有一个 DLL,它通过单个套接字连接到服务器。 我面临以下问题:如果服务器的 IP 地址和端口为假或服务器已关闭,则使用此 DLL 的应用程序将冻结半分钟。 我的想法是使用非阻塞套接字来避免该问题,方法是显示一个指示连接进度的窗口,并允许取消此过程。 但是我没有窗口处理程序,我怎么能使用 WSAAsyncSelect 函数呢?
【问题讨论】:
【参考方案1】:如果您想使用 WSAAsyncSelect 类型的套接字,那么您的 Dll 将需要创建至少一个消息窗口来处理套接字事件。由于窗口将永远不可见,它的 WindowProc 将仅包含您可能传递给 WSAAsyncSelect 的自定义消息 (WM_USER+1) 的处理程序 - 其他所有内容都直接传递给 DefWindowProc。
无论如何,您都必须在连接时创建一个无模式的进度窗口以显示您的连接 UI。
【讨论】:
【参考方案2】:在我看来,您的根本问题是 IO 操作阻塞了您的 UI 线程。我会尝试将连接移动到一个单独的线程,因为它不应该阻塞 UI,而是与其并行运行。无论如何,将 IO 操作与 UI 线程分开是一个好主意。您可以使用信号量等正常机制在两个线程之间进行通信。
如果可以的话,看看 boost 线程,它们很容易使用。
【讨论】:
【参考方案3】:我建议使用适当的库,例如 boost::asio,它也是跨平台的并提供异步连接处理功能
【讨论】:
【参考方案4】:另一种使用非阻塞套接字的方法是使用select() function。
可以通过检查socket是否可写来判断连接是否完成,
您还可以在select
上指定超时。
【讨论】:
【参考方案5】:我同意使用非阻塞套接字,然后 select() 是在 C 中使用的方法。这里有一些基本示例代码,在 Windows 上执行非阻塞连接,超时时间为 15 秒。
int s;
long on = 1L;
int socketsFound;
struct timeval timeout;
fd_set wfds;
struct addrinfo *addrInfo,
s = socket(addrInfo->ai_family, addrInfo->ai_socktype, addrInfo->ai_protocol);
if (s < 0)
/* Error */
return ;
if (ioctlsocket(s, FIONBIO, (u_long *)on))
/* Error */
return ;
if (connect(s, addrInfo->ai_addr, addrInfo->ai_addrlen) < 0)
if (WSAGetLastError()!= WSAEWOULDBLOCK)
/* Connection failed */
return;
/* 15 second timeout */
timeout.tv_sec = (long)15;
timeout.tv_usec = 0;
FD_ZERO(&wfds);
FD_SET(s, &wfds);
socketsFound = select((int)s+1, NULL, &wfds, NULL, &timeout);
if (socketsFound > 0 && FD_ISSET( s, &wfds ))
/* Connected */
【讨论】:
【参考方案6】:使用 WSAAsyncSelect 并不是 Winsock 中非阻塞套接字的唯一选择。这实际上是老的 Winsock 1.1/Win16 做异步套接字的方式。
Winsock 2+/Win32 的方式是使用重叠 I/O。请参阅this article 以了解与套接字重叠 I/O 的说明。
【讨论】:
【参考方案7】:将HWND_MESSAGE
作为父窗口传递给CreateWindow
。这将创建一个没有窗口的消息队列。当然,您仍然需要 WndProc,因为您将在其中处理消息。
【讨论】:
以上是关于DLL 中的非阻塞套接字(无窗口)的主要内容,如果未能解决你的问题,请参考以下文章
没有 ConnectEx 的 Windows 上的非阻塞套接字连接