Запись и отправка данных одновременно с использованием неблокирующего сокета - PullRequest
0 голосов
/ 07 июня 2019

Я хочу создать простой чат-клиент, в котором клиенты присоединяются к серверу и отправляют на него сообщения, который затем, в свою очередь, отправляет эти сообщения всем другим подключенным клиентам.

Проблема, с которой я сталкиваюсь, связана с вычислениемузнать, как клиенты могут отправлять сообщения на сервер, а также одновременно получать входящие сообщения от других клиентов через сервер.Проблема, с которой я сталкиваюсь, заключается в том, что любой метод, который я нахожу для ввода данных, всегда приводит к зависанию потока (так как он ожидает ввода от пользователя).

Существует аналогичная проблема Winsock -Как получать и отправлять данные одновременно? .Ответ в основном предусматривает три способа решения этой проблемы:

  1. Использование блокирующих сокетов с потоками чтения / записи
  2. Использование неблокирующего сокетного ввода-вывода с опросом событий
  3. И еще есть асинхронный сокет ввода-вывода с использованием перекрывающихся входов-выходов, портов завершения ввода-вывода или зарегистрированных расширений ввода-вывода

Я реализовал первый, см. 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 () - Синхронное мультиплексирование ввода-вывода , и я не получаю эту ошибку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...