第二次进行客户端连接时,没有服务器OnAccept通知

9
我写了一个MFC C++应用程序,在该应用程序中,客户端进程通过TCP的MyCAsyncSocket::Connect与服务器进程进行连接。服务器进程会响应MyCAsyncSocket::OnAccept,并按照规定Detach该套接字,创建一个线程并将其Attach到该套接字上,然后读取正在发送的数据。MSDN指导将m_hSocket在Detach之后设置为NULL。

这个方法可以正常工作,但仅限于第一次。第二次客户端尝试连接到相同的套接字地址时,没有OnAccept通知。以下是服务器代码:
void MyCAsyncSocket::OnAccept( int nErrorCode )
{
  BOOL socketResult = FALSE;

  CAsyncSocket syncSocket;

  Accept( syncSocket );
  AsyncSelect( FD_READ | FD_CLOSE );

  SOCKET socket = syncSocket.Detach();
  m_hSocket = NULL; // prescribed by msdn

  ... // go attach the socket in a worker thread, read the socket and do work

  // try to re-establish listener.
  ...Create( // error: attempt 2: ASSERT(m_hSocket == INVALID_SOCKET)
    endPoint.portNumber, // ok: same as client port number
    SOCK_STREAM,
    FD_READ | FD_WRITE | FD_ACCEPT | FD_CONNECT | FD_CLOSE,
    endPoint.ipAddress // ok: same as client ip address
  );

  ...Listen(); // error: attempt 1: no error case, but still doesn't work


  CAsyncSocket::OnAccept( nErrorCode );
}

尝试一:在Detach之后的OnAccept中,我尝试用Listen进行后续操作,但是遇到了这个监听错误:“WSAENOTSOCK:描述符不是套接字”。不确定这是什么意思。
尝试二:然后我尝试在后续的Listen之前进行Create,但这导致了一个断言:ASSERT(m_hSocket == INVALID_SOCKET);,其定义为:
/*
* This is used instead of -1, since the
* SOCKET type is unsigned.
*/
#define INVALID_SOCKET  (SOCKET)(~0)

在原型代码中,我仅仅销毁了监听套接字并重新创建了它,但对于生产代码来说,这是不可接受的,因为Detach和重新Attach的整个概念是确保套接字线程的监听能力不会中断超过毫秒级。有人知道为后续的Connection准备套接字的正确语义应该是什么吗?
1个回答

2
如果我看得没错的话,你在监听套接字上调用了 AsyncSelect(FD_READ|FD_CLOSE) 方法 - 而实际上你想要在新接受的套接字(syncSocket) 上调用它。 我认为调用 AsyncSelect(FD_READ|FD_CLOSE) 可能会清除监听套接字上的 FD_ACCEPT 通知,从而确保在将来连接到监听套接字时不会调用 OnAccept。
此外,当你在上面设置 m_hSocket = NULL 时,你将 NULL 值赋给了监听套接字的句柄,而不是新接受的套接字(syncSocket) 的句柄。
此外,如果我正确地阅读 MSDN (https://msdn.microsoft.com/en-us/library/05sz8hz8.aspx),Detach() 方法本身会将相关句柄设置为 NULL,因此您不需要自己执行此操作。[我认为]你也不能这样做 - 因为 m_hSocket 应该是 syncSocket 的私有成员。
我希望你的 OnAccept 代码看起来更像这样:
void MyCAsyncSocket::OnAccept( int nErrorCode )
{
  BOOL socketResult = FALSE;

  CAsyncSocket syncSocket;

  Accept( syncSocket );

  SOCKET socket = syncSocket.Detach();

  ... // go attach the socket in a worker thread, which reads the socket and does work

}

现在可以工作了。我删除了AsyncSelect( FD_READ | FD_CLOSE );m_hSocket = NULL;语句,第二个OnAccept通知成功传递。当然,AsyncSelect( FD_ACCEPT | FD_READ | FD_CLOSE );也可以工作。干得好。 - rtischer8277

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接