第二次进行客户端连接时没有服务器 OnAccept 通知
No server OnAccept notification when doing client Connect a second time
我编写了一个 MFC C++ 应用程序,其中我的客户端进程对我的服务器进程执行 TCP MyCAsyncSocket::Connect
。服务器进程以 MyCAsyncSocket::OnAccept
响应,然后 Detach
按照规定使用套接字,创建一个线程 Attach
使用该套接字,然后读取正在发送的数据。 MSDN 规定 m_hSocket 在 Detach
.
之后设置为 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:在 Detach
之后的 OnAccept
中,我尝试使用 Listen
跟随,但我收到此侦听错误:“WSAENOTSOCK:描述符不是套接字”。不知道这是什么意思。
尝试 2:然后我尝试在后续 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
ing 和 reAttach
的整个想法ing 是为了确保套接字线程的侦听能力永远不会中断超过微秒。
有人知道为随后的 Connect
离子准备套接字的正确语义应该是什么吗?
如果我没看错,你在 listening 套接字上调用 AsyncSelect(FD_READ|FD_CLOSE) - 我想你真的想要在新接受的套接字 (syncSocket) 上调用它。
我希望调用 AsyncSelect(FD_READ|FD_CLOSE) 可以清除侦听套接字上的 FD_ACCEPT 通知 - 从而确保在以后建立连接时不会调用 OnAccept到监听套接字。
进一步 - 当您在上面设置 m_hSocket = NULL 时,您将 listening 套接字的句柄设为 NULL,而不是新接受的套接字的句柄(同步套接字)。
此外,如果我没有正确阅读 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
}
我编写了一个 MFC C++ 应用程序,其中我的客户端进程对我的服务器进程执行 TCP MyCAsyncSocket::Connect
。服务器进程以 MyCAsyncSocket::OnAccept
响应,然后 Detach
按照规定使用套接字,创建一个线程 Attach
使用该套接字,然后读取正在发送的数据。 MSDN 规定 m_hSocket 在 Detach
.
它工作正常,但只有一次。客户端第二次尝试 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:在 Detach
之后的 OnAccept
中,我尝试使用 Listen
跟随,但我收到此侦听错误:“WSAENOTSOCK:描述符不是套接字”。不知道这是什么意思。
尝试 2:然后我尝试在后续 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
ing 和 reAttach
的整个想法ing 是为了确保套接字线程的侦听能力永远不会中断超过微秒。
有人知道为随后的 Connect
离子准备套接字的正确语义应该是什么吗?
如果我没看错,你在 listening 套接字上调用 AsyncSelect(FD_READ|FD_CLOSE) - 我想你真的想要在新接受的套接字 (syncSocket) 上调用它。
我希望调用 AsyncSelect(FD_READ|FD_CLOSE) 可以清除侦听套接字上的 FD_ACCEPT 通知 - 从而确保在以后建立连接时不会调用 OnAccept到监听套接字。
进一步 - 当您在上面设置 m_hSocket = NULL 时,您将 listening 套接字的句柄设为 NULL,而不是新接受的套接字的句柄(同步套接字)。
此外,如果我没有正确阅读 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
}