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

时间:2016-08-12 15:46:48

标签: c++ sockets mfc tcplistener

我编写了一个MFC C ++应用程序,其中我的客户端进程对我的服务器进程执行TCP MyCAsyncSocket::Connect。服务器进程以MyCAsyncSocket::OnAccept响应,然后Detach按照规定的套接字创建一个线程Attach es该套接字,然后读取正在发送的数据。 MSDN规定在Detach之后将m_hSocket设置为NULL。

它工作正常,但只有一次。客户端第二次尝试Connect到同一个套接字地址时,不会发生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 );
}

尝试1:OnAccept之后的Detach我尝试跟随Listen,但是我收到了这个监听错误:“WSAENOTSOCK:描述符不是套接字”。不确定这意味着什么。

尝试2:然后我尝试在后续Create之前执行Listen,但这会导致断言:ASSERT(m_hSocket == INVALID_SOCKET);,其定义为:

/*
* This is used instead of -1, since the
* SOCKET type is unsigned.
*/
#define INVALID_SOCKET  (SOCKET)(~0)

在原型代码中,我只是销毁了侦听器套接字并从头开始重新创建它,但是对于生产代码,这是不可接受的,因为Detach和re Attach的整个概念是确保套接字线程的监听能力永远不会中断超过几微秒。

有人知道为后续Connect离子准备套接字应该是什么样的语义吗?

1 个答案:

答案 0 :(得分:2)

如果我正确读取此内容,则在侦听套接字上调用AsyncSelect(FD_READ | FD_CLOSE) - 我认为您实际上想在新接受的套接字(syncSocket)上调用它。

我希望调用AsyncSelect(FD_READ | FD_CLOSE)可以清除侦听套接字上的FD_ACCEPT通知 - 从而确保在将来连接到侦听套接字时不会调用OnAccept。

此外 - 当您在上面设置m_hSocket = NULL时,您将忽略侦听套接字的句柄,而不是新接受的套接字(syncSocket)的句柄。

此外,如果我正确地读取MSDN(https://msdn.microsoft.com/en-us/library/05sz8hz8.aspx),Detach()方法本身会将相关句柄弄清楚,而您自己也不需要这样做。 [不,我希望,你能 - 因为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

}