【发布时间】:2016-04-03 14:30:53
【问题描述】:
所以我正在构建一个聊天服务器,现在我正在尝试回显来自客户端的所有消息。目前,我一收到消息,就会在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);
}
}
}
}
【问题讨论】:
-
1) (假设这里是 TCP) send() 和 recv 有一个返回值。用它。并处理部分读/写。 2) 接收后不能在缓冲区上使用 strlen(),因为它不一定是 NUL 终止的。 3) 从 send/recv/select 返回 -1 并不总是错误。它可能是中断的系统调用、EWOULDBLOCK,甚至是资源不足的情况。 4) 在 accept() 之后,您可能希望将 new_fd 添加到读取的 fd_fds 中。
-
TCP,没错。感谢您指出strlen()。关于返回值,所以你是说,总是会有两次对send()的调用,但我只需要跟踪第一次调用发送了多少数据,然后在第二次或第三次调用中发送其余数据? -
我只是指出了明显的错误。恕我直言,永远不会有第二次或第三次发送调用,因为新的 fd 不在 write fd_set 中,也不在 read_set 中。 (两者都是主集的副本)
-
固定接受()。谢谢。
-
没错。使用返回值来计算你走了多远,以及接下来需要做什么。请不要纠正问题中的错误。