我想创建一个简单的聊天客户端,客户端将客户端加入服务器并向其发送消息,然后依次将这些消息发送给所有其他连接的客户端。
我遇到的问题是弄清楚如何使客户端能够向服务器发送消息,同时又能够通过服务器同时从其他客户端接收入站消息。我遇到的问题是,我发现要接受输入的任何方法都会使线程挂起(因为它正在等待用户的输入)。
存在类似的问题Winsock - How to receive and send data simultaneously?。答案主要提供三种解决方法:
我已经实现了第一个,请参见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
示例,但我没有
得到那个错误。