2009-11-24 76 views
1

我有一个DLL通过一个套接字连接到服务器。 我面临以下问题:如果服务器的IP地址&端口为假或服务器关闭,则使用此DLL的应用程序将冻结,直到半分钟。 我的想法是使用非阻塞套接字来避免这个问题,通过显示一个指示连接进度的窗口,并且允许取消这个过程。 但我怎么能使用WSAAsyncSelect函数,因为我没有窗口处理程序?DLL中无阻塞套接字(无窗口)

回答

2

在我看来,你的根本问题是IO操作阻塞你的UI线程。我会尝试将连接移动到单独的线程,因为它不应该阻止用户界面,而是与其并行运行。无论如何,保持IO操作与UI线程分离是一个好主意。您可以使用正常机制(如信号量)在两个线程之间进行通信。

如果可以,请查看助推线程,它们非常易于使用。

1

我建议使用一个合适的库,例如boost::asio这也是跨平台,并提供异步连接处理能力

3

如果你想使用WSAAsyncSelect型插座那么你的DLL将需要至少创建一个消息窗口来处理套接字事件。由于该窗口永远不可见,因此它的WindowProc仅包含用于自定义消息(WM_USER + 1)的处理程序(可能是您传递给WSAAsyncSelect) - 其他所有内容都直接转到DefWindowProc。

无论如何你都必须创建一个无模式的进度窗口来显示你的连接用户界面。

0

使用非阻塞套接字的另一种方法是使用select() function

您可以通过检查,看是否插座可写,
确定连接的完成,你还可以指定在select超时。

0

我同意使用非阻塞套接字,然后选择()是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 */ 
} 
0

使用WSAAsyncSelect并不是Winsock中非阻塞套接字的唯一选择。这实际上是旧的Winsock 1.1/Win16做异步套接字的方式。

Winsock 2 +/Win32的方式是使用重叠的I/O。有关套接字重叠I/O的说明,请参阅this article

0

通过HWND_MESSAGE作为父窗口到CreateWindow。这将创建一个没有窗口的消息队列。当然,您仍然需要一个WndProc,因为这是您处理消息的地方。