Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

No server OnAccept notification when doing client Connect a second time

I have written an MFC C++ app where my client process does a TCP MyCAsyncSocket::Connect to my server process. The server process responds with an MyCAsyncSocket::OnAccept which then Detaches the socket as is prescribed, creates a thread which Attaches that socket, which then reads the data being sent. MSDN prescribes that m_hSocket be set to NULL after Detach.

It works fine, but only one time. The second time the client tries to Connect to the same socket address, no OnAccept notification occurs. Here is the server code:

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 );
}

Attempt 1: In OnAccept after the Detach I tried following with a Listen, but I get this listen error: “WSAENOTSOCK: The descriptor is not a socket”. Not sure what this means.

Attempt 2: I then tried doing a Create before the follow-up Listen, but this caused an assert: ASSERT(m_hSocket == INVALID_SOCKET); which is defined as:

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

In the prototype code I merely destroyed the listener socket and re-created it from scratch, but for production code, this is not acceptable since the whole idea of Detaching and reAttaching is to assure that the socket thread’s listening capability is never interrupted for more than microseconds.

Does someone know what the proper semantics should be for preparing the socket for subsequent Connections?

like image 375
rtischer8277 Avatar asked Aug 12 '16 15:08

rtischer8277


1 Answers

If I'm reading this correctly, you call AsyncSelect(FD_READ|FD_CLOSE) on the listening socket - and I think you actually want to call that on the newly accepted socket (syncSocket).

I would expect that calling AsyncSelect(FD_READ|FD_CLOSE) may clear the FD_ACCEPT notification on the listening socket - thus ensuring that no OnAccept is called when future connections are made to the listening socket.

Further - when you set m_hSocket = NULL above, you're NULL-ing out the handle of the listening socket, not that of the newly accepted socket (syncSocket).

Furthermore, if I'm reading MSDN correctly (https://msdn.microsoft.com/en-us/library/05sz8hz8.aspx), the Detach() method itself NULLs out the relevant handle, and you do not need to do this yourself. [ nor, I expect, can you - since m_hSocket ought to be a private member of syncSocket ]

I would expect your OnAccept code to look more like:

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

}
like image 148
Kevin Avatar answered Nov 15 '22 21:11

Kevin