当 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);
}
}
}
最佳答案
你应该有FD_ZERO
和FD_SET
s 在调用 select 函数之前。
例如
int res = 0;
for(;;){
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
fdmax = 0;
size_t fd_index;
for (fd_index=0; fd_index<num_of_fd; fd_index++)
{
FD_SET(fd_array[fd_index], &read_fds);
FD_SET(fd_array[fd_index], &write_fds);
if (fdmax < fd_array[fd_index])
fdmax = fd_array[fd_index];
}
// write_fds = master;
res = select(fdmax+1, &read_fds, &write_fds, NULL, NULL);
if( res == 0 )
{
// TIMEOUT ...not your case
}
else if( res < 0 )
{
perror("Select error: ");
}
else
{
// process your data
}
你不能写
read_fds = master;
因为fd_set
是一个复杂的结构。
编辑
正如@jeremyP评论的那样sent < 0
应该是sent > 0
关于c - 如何在 C 中的 write_fds 和 select() 中正确设置标志,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37838490/