所以我正在构建一个聊天服务器,现在我正在尝试回显来自客户端的所有消息。目前,我一收到消息,就会在
readData()
内发回。然而,一旦我发送,select()
就会通知write_fds
并且sendData()
会被呼叫,即使我已经打电话给send()
我发送数据的大部分调用都在
readData()
内。
select()
和 write_fds
的正确方法吗?select()
我想要发送数据而不需要两次调用send()
? 对我来说,必须处理两个
send()
电话似乎是多余的。
int readData(int j){
// get message from the client
recv(j, client_buffer , 6000 , 0);
// echo message to the client
send(j, client_buffer, strlen(client_buffer));
}
int sendData(int j){
send(j, buf, nbytes, 0);
}
for(;;){
read_fds = master;
write_fds = master;
if(select(fdmax+1, &read_fds, &write_fds, NULL, NULL) == -1){
exit(4);
}
for(i = 0; i <= fdmax; i++){
if(FD_ISSET(i, &read_fds)){
if(i == listener){
// handle new connections
addrlen = sizeof remoteaddr;
newfd = accept(listener, (struct sockaddr *)&addr, &addrlen);
FD_SET(newfd, &master);
if(newfd > fdmax) fdmax = newfd;
}else{
// we got some data from a client
readData(i);
}
}
if(FD_ISSET(i, &write_fds)){
if(i != listener){
// send data when notified
sendData(i);
}
}
}
}
我不建议直接在
sendData()
内部致电 readData()
。它们应该分开存放。让readData()
将接收到的数据返回给调用者,并让调用者决定如何处理它。如果调用者想要发送数据,则可以根据需要调用 sendData()
。
要解决
select()
问题,您需要为传出数据创建每个套接字缓冲区。并确保套接字以非阻塞模式运行。
如果在缓冲区为空时调用
sendData()
,则 send()
尽可能多地调用者的数据。 send()
将返回它实际接受的字节数。如果 send()
报告 EWOULDBLOCK
或 EAGAIN
错误,请停止发送并将所有未发送的数据附加到缓冲区末尾。如果在缓冲区不为空时调用
sendData()
,只需将新数据追加到缓冲区末尾并退出,根本不调用send()
。每当
select()
报告套接字可写时,send()
当前缓存在该套接字缓冲区中的任何内容(如果有)。对于每个成功的 send()
,从缓冲区前面删除报告的字节数。如果缓冲区耗尽或 send()
失败,请停止发送。