我有一个异步套接字并调用connect()+ GetLastError(),它返回WSA_WOULD_BLOCK,如预期的那样。所以我开始“接收/读取”线程并将事件订阅到FD_READ和FD_CLOSE。
故事是:连接将按顺序失败,因为服务器未启动并正在运行。我的理解是我的接收线程很快会得到FD_CLOSE,我需要跟进清理工作。
没有发生。我应该多久收到FD_CLOSE?这是正确的方法吗?还有其他方法可以理解connect()失败了吗?如果套接字未连接,我会收到FD_CLOSE吗?
在成功调用DoConnect()之后,我确实开始接收线程和订阅事件,我担心赛车条件会阻止我获得FD_CLOSE。
以下是一些代码:
int RecvSocketThread::WaitForData()
{
int retVal = 0
while (!retVal)
{
// sockets to pool can be added on other threads.
// please validate that all of them in the pool are connected
// before doing any reading on them
retVal = DoWaitForData();
}
}
int RecvSocketThread::DoWaitForData()
{
// before waiting for incoming data, check if all sockets are connected
WaitForPendingConnection_DoForAllSocketsInThePool();
// other routine to read (FD_READ) or react to FD_CLOSE
// create array of event (each per socket) and wait
}
void RecvSocketThread::WaitForPendingConnection_DoForAllSocketsInThePool()
{
// create array and set it for events associated with pending connect sockets
HANDLE* EventArray = NULL;
int counter = 0;
EventArray = new HANDLE[m_RecvSocketInfoPool.size()];
// add those event whose associated socket is still not connected
// and wait for FD_WRITE and FD_CLOSE. At the end of this function
// don't forget to switch them to FD_READ and FD_CLOSE
while (it != m_RecvSocketInfoPool.end())
{
RecvSocketInfo* recvSocketInfo = it->second;
if (!IsEventSet(recvSocketInfo->m_Connected, &retVal2))
{
::WSAEventSelect(recvSocketInfo->m_WorkerSocket, recvSocketInfo->m_Event, FD_WRITE | FD_CLOSE);
EventArray[counter++] = recvSocketInfo->m_Event;
}
++it;
}
if (counter)
{
DWORD indexSignaled = WaitForMultipleObjects(counter, EventArray, WaitAtLeastOneEvent, INFINITE);
// no matter what is further Wait doen't return for failed to connect socket
if (WAIT_OBJECT_0 <= indexSignaled &&
indexSignaled < (WAIT_OBJECT_0 + counter))
{
it = m_RecvSocketInfoPool.begin();
while (it != m_RecvSocketInfoPool.end())
{
RecvSocketInfo* recvSocketInfo = it->second;
if (IsEventSet(recvSocketInfo->m_Event, NULL))
{
rc = WSAEnumNetworkEvents(recvSocketInfo->m_WorkerSocket,
recvSocketInfo->m_Event, &networkEvents);
// Check recvSocketInfo->m_Event using WSAEnumnetworkevents
// for FD_CLOSE using FD_CLOSE_BIT
if ((networkEvents.lNetworkEvents & FD_CLOSE))
{
recvSocketInfo->m_FD_CLOSE_Recieved = 1;
*retVal = networkEvents.iErrorCode[FD_CLOSE_BIT];
}
if ((networkEvents.lNetworkEvents & FD_WRITE))
{
WSASetEvent(recvSocketInfo->m_Connected);
*retVal = networkEvents.iErrorCode[FD_WRITE_BIT];
}
}
++it;
}
}
// if error - DoClean, if FD_WRITE (socket is writable) check if m_Connected
// before do any sending
}
}
答案 0 :(得分:2)
如果FD_CLOSE
失败,您将不会收到connect()
通知。您必须订阅FD_CONNECT
才能检测到。这在connect() documentation:
使用非阻塞套接字,无法完成连接尝试 立即。在这种情况下,connect将返回SOCKET_ERROR,并且 WSAGetLastError将返回WSAEWOULDBLOCK。在这种情况下,有 三种可能的情况:
•使用选择功能确定完成 通过检查套接字是否可写来连接请求。
•如果应用程序正在使用WSAAsyncSelect来表示对此感兴趣 连接事件,然后应用程序将收到FD_CONNECT 表示连接操作已完成的通知 (成功与否)。
•如果应用程序使用WSAEventSelect表示对此感兴趣 连接事件,然后将发信号通知相关的事件对象 表示连接操作已完成(成功或 不是)。
当connect()
为HIWORD(lParam)
时,LOWORD(lParam)
的结果代码将显示在事件的FD_CONNECT
值中。如果结果代码为0,connect()
成功,否则它将是WinSock错误代码。
答案 1 :(得分:1)
如果您致电connect()
并获得阻止通知,则必须通过here所述的三种方法之一编写更多代码来监控connect()
完成(成功或失败)。< / p>
使用非阻塞套接字,无法完成连接尝试 立即。在这种情况下,connect将返回SOCKET_ERROR,并且 WSAGetLastError将返回WSAEWOULDBLOCK。在这种情况下,有 三种可能的情况:
•使用select功能确定连接完成 请求通过检查套接字是否可写。
•如果 应用程序正在使用WSAAsyncSelect来表示对连接的兴趣 事件,然后应用程序将收到FD_CONNECT通知 表示连接操作已完成(成功或 不)。
•如果应用程序使用WSAEventSelect来表示兴趣 在连接事件中,然后关联的事件对象将是 发出信号表示连接操作已完成 (成功与否)。
答案 2 :(得分:0)
我想我需要在创建套接字句柄后启动Receving线程,但是在调用connect之前。在异步套接字上调用connect之后创建它为时已晚。 对于同步套接字,那两个调用createsocket()和connect()只是两个连续的行。不适用于非阻塞。
在这种情况下,在接收线程开始时,我需要检查FD_CONNECT和/或FD_WRITE,以便获知连接尝试状态。