使用非阻塞套接字同时接收和发送数据

时间:2019-06-07 03:49:05

标签: c++ c sockets

我想创建一个简单的聊天客户端,客户端将客户端加入服务器并向其发送消息,然后依次将这些消息发送给所有其他连接的客户端。

我遇到的问题是弄清楚如何使客户端能够向服务器发送消息,同时又能够通过服务器同时从其他客户端接收入站消息。我遇到的问题是,我发现要接受输入的任何方法都会使线程挂起(因为它正在等待用户的输入)。

存在类似的问题Winsock - How to receive and send data simultaneously?。答案主要提供三种解决方法:

  1. 使用具有读写线程的阻塞套接字
  2. 将非阻塞套接字I / O与事件轮询一起使用
  3. 然后使用异步I / O,重叠I / O,I / O完成端口或注册的I / O扩展

我已经实现了第一个,请参见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 socket: recv and send data simultaneously中的答案,并尝试将STDIN_FILENO添加到readfds中,但是在那之后,如果我运行客户端,则会出现错误Select call failed with error code: 10038。 >

Windows Sockets Error Codes给出了可能的错误代码10038的原因

  

对于select,fd_set的成员无效。

我不知道为什么,因为我在select()—Synchronous I/O Multiplexing上用select尝试了类似的STDIN_FILENO示例,但我没有 得到那个错误。

0 个答案:

没有答案