Я хочу создать простой чат-клиент, в котором клиенты присоединяются к серверу и отправляют на него сообщения, который затем, в свою очередь, отправляет эти сообщения всем другим подключенным клиентам.
Проблема, с которой я сталкиваюсь, связана с вычислениемузнать, как клиенты могут отправлять сообщения на сервер, а также одновременно получать входящие сообщения от других клиентов через сервер.Проблема, с которой я сталкиваюсь, заключается в том, что любой метод, который я нахожу для ввода данных, всегда приводит к зависанию потока (так как он ожидает ввода от пользователя).
Существует аналогичная проблема Winsock -Как получать и отправлять данные одновременно? .Ответ в основном предусматривает три способа решения этой проблемы:
- Использование блокирующих сокетов с потоками чтения / записи
- Использование неблокирующего сокетного ввода-вывода с опросом событий
- И еще есть асинхронный сокет ввода-вывода с использованием перекрывающихся входов-выходов, портов завершения ввода-вывода или зарегистрированных расширений ввода-вывода
Я реализовал первый, см. WinsockExample
Теперь я хочу решить эту проблему, используя второй метод, и я много раз ищу и пробую, используя select
.Но я все еще не мог получить то, что хотел, клиент все еще блокировался при чтении ввода от пользователя и не мог выводить полученное сообщение от других клиентов одновременно.
Пока мой код клиента.
while ( 1 )
{
fd_set readfds, writefds;
FD_ZERO( &readfds );
FD_ZERO( &writefds );
/* printf("%d %d\n", ConnectSocket, STDIN_FILENO); */
FD_SET( ConnectSocket, &readfds );
/* FD_SET(0, &readfds); */
FD_SET( ConnectSocket, &writefds );
iResult = select( ConnectSocket, &readfds, &writefds, NULL, NULL );
if ( FD_ISSET( ConnectSocket, &readfds ) )
{
/* we got data from server, read it */
printf( "Receiving message...\n" );
iResult = recv( ConnectSocket, recvbuf, recvbuflen, 0 );
if ( iResult > 0 )
{
memset( &message, 0, sizeof(message) );
memcpy( &message, recvbuf, sizeof(message) );
SetConsoleColour( &Attributes, FOREGROUND_INTENSITY | FOREGROUND_RED );
printf( "Received Message from SOCKET %s: %s\n", message.username, message.content );
ResetConsoleColour( Attributes );
} else if ( iResult == 0 )
{
printf( "Connection closed\n" );
} else {
printf( "recv failed with error: %d\n", WSAGetLastError() );
}
}
if ( FD_ISSET( ConnectSocket, &writefds ) )
{
/* send data to server */
printf( "\n\nPlease input message you want to send: " );
memset( message.content, 0, sizeof(message.content) );
message.content_length = read( STDIN_FILENO, message.content, 1024 ) - 1;
message.content[message.content_length] = '\0';
memset( sendbuf, 0, sizeof(sendbuf) );
/* convert struct type to char[] */
memcpy( sendbuf, &message, sizeof(message) );
/* Send an initial buffer */
iResult = send( ConnectSocket, sendbuf, sizeof(sendbuf), 0 );
printf( "Send Message: %s\n", message.content );
}
}
Может кто-нибудь дать мне подсказку, как реализовать это, используя non-blocking socket
?
-------------------------------- Edit1 ------------------------------
После запуска клиентского кода я получу вывод Please input message you want to send:
.Тем не менее, я думаю, что он должен остановиться на select
, так как нет операций ни на одном из членов readfds или writefds.
Я следовал за ответом в c сокете: recv и отправлять данные одновременно ипопробуйте добавить STDIN_FILENO
в readfds
, но после этого, если я запустлю клиент, я получу ошибку Select call failed with error code: 10038
.
Коды ошибок Windows Sockets дает возможную причину для кода ошибки10038
для выбора, член fd_set недействителен.
Я не знаю почему, поскольку я попробовал аналогичный пример select
с STDIN_FILENO
on select () - Синхронное мультиплексирование ввода-вывода , и я не получаю эту ошибку.