Ваша fd_set
установка в порядке, но вы не проверяете возвращаемое значение select()
для > 0
перед входом в цикл чтения.
Ваш цикл чтения вызывает break
в неправильном видеместо, на самом деле он не должен звонить break
вообще .Вы выходите из цикла, как только любой клиент отправляет данные, игнорируя других клиентов, которые могут также отправлять данные, ожидающие чтения.Вам необходимо пройти через все чтение fd_set
из каждого сокета, который находится в состоянии чтения.
Ваш цикл чтения не должен вызывать exit()
, если recv()
не удается.Просто close()
неисправный сокет, удалите этот сокет из players[]
и перейдите к следующей итерации цикла.
Если recv()
вернет -1, обязательно проверьте errno
для EWOULDBLOCK
и EAGAIN
, поскольку они не являются фатальными ошибками.Кроме того, если recv()
вернет 0, клиент отключился.
Попробуйте что-то вроде этого:
fd_set player_fd_set;
FD_ZERO(&player_fd_set);
int max_fd = players[0].connected_socket_on_master;
for (int i = 0; i < num_players; ++i)
{
FD_SET(players[i].connected_socket_on_master, &player_fd_set);
if (players[i].connected_socket_on_master > max_fd)
max_fd = players[i].connected_socket_on_master;
}
if (select(max_fd + 1, &player_fd_set, NULL, NULL, NULL) > 0)
{
int offset = 0;
for (int i = 0; i < num_players; ++i)
{
printf("Check fd # %d\n", i);
if (!FD_ISSET(players[offset].connected_socket_on_master, &player_fd_set))
continue;
printf("Coming from player # %d\n", i);
ssize_t recvStatus = recv(players[offset].connected_socket_on_master, potato.trace, sizeof(potato.trace), 0);
if (recvStatus > 0)
{
// process potato.trace up to recvStatus bytes as needed...
++offset;
continue;
}
if (recvStatus < 0)
{
if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
{
// no more data to read right now...
++offset;
continue;
}
printf("Error: Could not recv final potato from player # %d\n", i);
}
else
printf("Player # %d disconnected\n", i);
close(players[offset].connected_socket_on_master);
for(int j = i+1; j < num_players; ++j)
players[j-1] = players[j];
--num_players;
}
}