私は2つのスレッドを持っています:
スレッド A: select()ループです。新しい接続の受け入れ、データの受信など、読み取り操作のソケット処理を実行します。
while (1) {
FD_ZERO(&fdReadSet);
numActiveSockets = 0;
for (std::unordered_map<SOCKET, TcpSocket*>::iterator it = m_sock_table.begin(); it != m_sock_table.end(); it++)
{
numActiveSockets++;
FD_SET(it->first, &fdReadSet);
}
int ret;
bool hasListen = false;
if (( ret = select(numActiveSockets, &fdReadSet, NULL, NULL, NULL)) == SOCKET_ERROR) {
printf("Select Failed, Error code = %d\n", WSAGetLastError());
return -1;
}
for (std::unordered_map<SOCKET, TcpSocket*>::iterator it = m_sock_table.begin(); it != m_sock_table.end(); it++)
{
if (FD_ISSET(it->first, &fdReadSet))
{
if (it->first == TcpSocket::m_listen_sock)
{
if (!hasListen)
{
sockaddr_in sock_addr;
int sockLength = sizeof(sock_addr);
SOCKET sock = accept(it->first, (sockaddr *) &sock_addr, &sockLength);
TcpSocket * socket = new TcpSocket();
socket->m_sock = sock;
m_sock_table[sock] = socket;
it = m_sock_table.begin();
hasListen = true;
}
}
else
{
char * buffer = it->second->GetWriteBuffer();
int numRead = recv(it->first, buffer, SOCKET_BUFFER_SIZE, 0);
if (numRead == SOCKET_ERROR)
{
int err = WSAGetLastError();
if (err == WSAECONNRESET)
{
printf("Connection [%i]: RESET Received. Closing Socket\n", it->first);
closesocket(it->first);
it = socketVector.erase(it->first); // iterator invalidated after erase
}
else
{
printf("Recv Failed. Error code = %d\n", err);
return -1;
}
}
else if (numRead == 0)//connection close
{
printf("Connection [%i]: Graceful exit. Closing Socket\n", it->first);
closesocket(it->first);
it = socketVector.erase(it->first); // iterator invalidated after erase
}
else {
/* Process received data */
}
}
}
}
}
スレッド B: アプリケーションがconnect()を実行して新しい接続を確立できるようにします。connect()が成功すると、返されたソケットが m_sock_table に追加されます。
すべてのソケットを保持するm_sock_tableというソケット テーブルがあります。このm_sock_tableを使用して、 select()で使用されるfdReadSetを初期化します。
- - - - - -問題 - - - - - - - - -
スレッド A がselect()によってブロックされ、同時にスレッド B がconnect()を介して新しい接続を確立した場合、 fdReadsetが新しい接続で更新されていないため、アプリケーションは新しい接続からデータを受信できません。接続されたソケット。
この問題を解決する良い方法は何でしょうか? それとも、最初からデザインが間違っているだけですか?