【问题标题】:How to exit a blocking connect() call in Windows?如何在 Windows 中退出阻塞的 connect() 调用?
【发布时间】:2017-07-15 09:06:21
【问题描述】:

有没有办法在 Windows 中退出阻塞的 connect() 调用?

请注意,我不想切换到非阻塞套接字。

【问题讨论】:

  • 不是答案,因为我在这里没有参考资料,但我隐约记得这是不可能的。
  • 也许CancelIoEx 可以满足您的需求?见msdn.microsoft.com/de-de/library/windows/desktop/…
  • 为什么不使用ConnectEx?
  • 您可以从单独的线程关闭套接字,或者在非阻塞模式下进行连接,然后在成功后切换回阻塞模式,并使用select() 轮询完成。或者只是等待连接超时,大约一分钟。
  • @Steve 您不需要将所有内容更改为非阻塞。只需在调用connect()之前将套接字置于非阻塞模式,然后在建立连接后将其恢复为阻塞模式。

标签: c sockets winapi winsock


【解决方案1】:

根据 MSDN connect page:

注意当发出阻塞 Winsock 调用(例如 connect)时,Winsock 可能需要等待网络事件才能完成调用。在这种情况下,Winsock 会执行警报等待,该等待可能会被安排在同一线程上的异步过程调用 (APC) 中断。在 APC 中发出另一个阻塞 Winsock 调用中断了同一线程上正在进行的阻塞 Winsock 调用将导致未定义的行为,并且 Winsock 客户端绝不能尝试。

所以如果你想取消connect调用,你必须从另一个线程来做:

/* apc callback */
VOID CALLBACK apc( _In_ ULONG_PTR data)
{
    /* warning, some synchronization should be added here*/
    printf("connect canceled by APC\n");
}

/* second thread code */
DWORD WINAPI cancel_thread_function(void* main_thread_handle)
{       
    /* wait 500 ms*/
    Sleep(500);

    if (test_if_connect_is_still_pending())
    {
        /* cancel connect */
        QueueUserAPC(apc, (HANDLE)main_thread_handle, (ULONG_PTR) NULL);
    }
    return 0;
}



/* The thread in which is executed the connect call */
HANDLE mainThread;
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &mainThread, 0, TRUE, DUPLICATE_SAME_ACCESS);

/* create cancelation thread */
CreateThread(NULL, 0, cancel_thread_function, , 0, NULL);

/* Warning: I should close the handles... */

connect(...);

IMO,EJP 解决方案是最好的(非阻塞 connect 并使用 select 进行测试)。

【讨论】:

  • APC 方法的缺点是它有一个竞争条件。在线程认为connect() 仍处于挂起状态后,connect() 可能会退出并且其调用线程在实际看到排队的 APC 之前继续前进,因此它将留在队列中并可能在将来中断其他事情。因此,connect() 退出后,如果线程仍在运行,则必须取消该线程,等待它实际终止,如果 APC 仍在队列中,则将其从队列中删除。
猜你喜欢
  • 2016-12-29
  • 2016-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-26
  • 1970-01-01
  • 1970-01-01
  • 2012-01-25
相关资源
最近更新 更多