【发布时间】:2016-06-15 14:36:06
【问题描述】:
当send() 缓冲区已满时,我在给定套接字的 write_fds 中设置了一个标志,并且下一次迭代尝试通过检查是否设置了 write_fds 来发送它。
在 write_fds 中为一个套接字设置标志可以正常工作。但是,如果我为多个套接字执行FD_SET(i, write_fds),则只有最后一个套接字显示为已设置,并且只有最后一个套接字获取数据。
如果我在select(2) 之前执行write_fds = master;,那么它们都显示为已设置,并且所有未发送的数据都发送到所有套接字,但select 总是返回。
我确定我一定做错了什么。
FD_ZERO(&master);
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
// socket setting...
// bind...
// listen...
FD_SET(listener, &master);
fdmax = listener; // so far, it's this one
for(;;){
read_fds = master; // copy it
// write_fds = master;
select(fdmax+1, &read_fds, &write_fds, NULL, NULL);
for(i = 0; i <= fdmax; i++){
if(FD_ISSET(i, &read_fds)) {
if(i == listener){
addrlen = sizeof remoteaddr;
newfd = accept(listener, (struct sockaddr * ) & remoteaddr, &addrlen);
FD_SET(newfd, &master);
if(newfd > fdmax)
fdmax = newfd;
fcntl(newfd, F_SETFL, fcntl(newfd, F_GETFL, 0) | O_NONBLOCK);
}else{
// do some reading and then... send
sent = send(i, buf, len, 0);
if ((sent < 0 || (sent == -1 && errno == EWOULDBLOCK))
FD_SET(i, &write_fds);
}
}
else if(FD_ISSET(i, &write_fds) && i != listener){
if((sent = send(i, buf, len - sent, 0)) == len - sent)
FD_CLR(i, &write_fds);
}
}
}
【问题讨论】:
-
如果你使用
gcc编译它并启用警告-Wall -Wextra,这样它会在编译时发现更多问题。 -
请注意,您需要在每次迭代时重建 FD 集;对
select的调用会修改输入/输出参数,从而破坏您设置的内容。见Is it necessary to reset the FD set betweenselect()system calls?、Are there any platforms where using structure copy on an FD set doesn't work?、Whyselect()always returns 0 after the first timeout?、Why isselectused on Linux?…… -
@JonathanLeffler 您能否详细说明重建 FD 集?这是否意味着我必须使用
FD_COPY?谢谢。 -
@PeterD:我添加了一些涉及该问题的半相关问题的链接。如果 FD_COPY() 可用(它没有被 POSIX 标准化),那么你应该可以使用它。请参阅有关使用结构副本的问题。
-
@JonathanLeffler 我明白了。感谢您的信息。
标签: c sockets select nonblocking