Я написал приложение MFC C ++, где мой клиентский процесс делает TCP MyCAsyncSocket::Connect
на мой серверный процесс. Серверный процесс отвечает MyCAsyncSocket::OnAccept
который тогда Detach
Если сокет, как это предписано, создает поток, который Attach
Это тот сокет, который затем читает отправляемые данные. MSDN предписывает, чтобы m_hSocket был установлен в NULL после 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 workCAsyncSocket::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
Инг и реAttach
Он должен гарантировать, что возможность прослушивания потока сокета никогда не прерывается более чем на микросекунды.
Кто-нибудь знает, какой должна быть правильная семантика для подготовки сокета к последующему Connect
Ионы?
Если я правильно читаю, вы вызываете 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
}
Других решений пока нет …