poll/select和writefds的最佳实践

poll/select和writefds的最佳实践,c,select,C,Select,select()和poll()的大多数示例的工作方式与此类似: int activity = select(FD_SETSIZE, &readfds , NULL , NULL , NULL); //... for (i = 0; i < max_clients; i++){ int sd = client_socket[i]; if (FD_ISSET(sd , &readfds)){ int len = read(sd , buffer,

select()
poll()
的大多数示例的工作方式与此类似:

int activity = select(FD_SETSIZE, &readfds , NULL , NULL , NULL);
//...
for (i = 0; i < max_clients; i++){
    int sd = client_socket[i];
    if (FD_ISSET(sd , &readfds)){
        int len = read(sd , buffer, 1024);
        if (len == 0){
            // disconnect
        }
        // echo server, send the data back
        send(sd , buffer , len , 0 );
    }
}
int activity=select(FD_SETSIZE,&readfds,NULL,NULL,NULL);
//...
对于(i=0;i
我看到这个代码的问题是-为什么我们认为/期望这个
send()
调用不会阻塞

即使我们执行套接字非阻塞,那么
send()
也不会阻塞,但会发送部分数据,甚至什么也不发送

也许我错了,但我认为我需要一个字符串数组,并在数据发送之前使用
writefds


有什么好的例子/实践吗?

您担心
send()
会阻塞是对的,因为它会阻塞

通常的解决方案是将套接字模式设置为非阻塞。然后,每次调用
send()
,检查是否:

  • 并非所有数据都已发送;或
  • errno
    查看它是
    EGAIN
    还是
    ewooldblock
  • 如果发生上述任何一种情况,那么系统的套接字缓冲区已满,您需要在“等待”期间将数据存储在某个位置,直到内核发送一些数据并释放系统套接字缓冲区中的空间


    现在,您可以将套接字添加到传递到
    select()
    writefds
    数组中,请求系统告知套接字何时可再次写入。当
    select()
    返回此套接字时,您应该再次尝试发送数据。如果在此期间有任何额外数据排队,请尝试发送该数据。如果您可以发送所有数据,请从
    writefds
    数组中删除套接字(或者每次调用
    select()
    )时都会返回该套接字)。

    如果您使用的是选择/轮询,则需要非阻塞。然后,读取和发送是处理全部数据还是部分数据取决于所使用的协议。这是一个特定的协议吗?由于一个附加的note send()可以发送的数据比您请求发送的数据少(假设TCP或类似的基于流的套接字),所以您还需要跟踪发送了多少数据,而不是简单地重新发送整个缓冲区,也不假设如果send()指示成功,则所有数据都已发送。因此,我基本上需要字符串数组,我将存储要发送的数据,并在部分数据发送后更新字符串,例如使用memmove()?还有一个相关问题,如果我在readfds或writefds中设置位,而实际上不需要它,这只会导致性能损失,对吗?@nos:Yes,但
    send()
    返回
    EAGAIN
    时不发送任何内容@尼克:没错,不过如果你想要非常高的性能,我不推荐
    memmove()。在典型的服务器中,这种性能损失是非常严重的。正确管理
    readfds
    writefds
    数组非常重要。@AndréCaron当然可以,但这只是发送0字节的特殊情况。send()调用可以发送从1到(包括)给定字节长度的任何数据,这不仅是send()给出EAGAIN的情况,而且是send()返回<'length'时的情况,即必须将(剩余)数据存储在某个位置,然后在select()指示可以发送时发送