如何缓冲send()和select()的数据?

时间:2009-06-15 19:29:26

标签: c++ sockets select asynchronous

虽然send()成功并且大部分时间都在发送所有数据,但情况并非总是如此。因此,建议人们使用write-fdset进行select()和poll()来检查套接字何时可写。

在保持易于理解的源代码的同时,通常的机制如何实际缓冲要发送的数据?

3 个答案:

答案 0 :(得分:1)

我对socket编程的* nix方面并不熟悉,但我在Win32端遇到了同样的问题。缓冲不是一个问题(你排队请求并查看写入完成从队列中提交下一个),真正的问题是需要缓冲信号,你实际上正在处理流量控制而你无法解决流量控制单独缓冲:总是有一个消费者比生产者慢,缓冲区基本上会失去控制。您必须将流控制向上传播到生成数据的任何模块,这使得接口非常复杂。所有“写入”请求必须支持指示流控制状态的返回码(即“停止写入,没有更多空间!”)和回调以邀请调用者恢复写入操作。

答案 1 :(得分:1)

由于我们处于C ++领域,您可以将数据存储在std :: vector

新数据会附加到矢量的末尾。当您收到套接字可写的通知时,请尝试发送完整的向量。 send()将返回真正发送的数量。然后简单地从向量的开头擦除该字节数:

std::vector<char> buffer;
...
if( ! buffer.empty() )
{
    int bytesRead = send( socket, &buffer[ 0 ], buffer.size(), flags );
    if( bytesRead > 0 )
        buffer.erase( 0, bytesRead );
    else
       // some error...
}

所以可能会有更多的错误检查,但你明白了吗?

相反排队每个单独的发送请求,这里的优点是你可以将多个更高级别的发送组合成一个套接字发送,假设你正在使用TCP?

但是正如Remus提到的那样,你的流量控制和API是一个棘手的问题 - 即如何阻止缓冲区变得太大?

答案 2 :(得分:1)

当编写需要以select()/ poll()循环为中心的OO时,需要一个很好的抽象。我总是发现Adaptive Communications Environment(ACE)Reactor类对此非常有用。 Doug Schmidt撰写了几本书“C ++网络编程”,涵盖了这个环境以及网络上的各种其他内容,包括The Design and Use of the ACE Reactor