简体   繁体   English

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

[英]How to buffer data for send() and select()?

While a send() succeeds with all data being sent most of the time, it is not always the case. 尽管send()在大多数时间都发送完所有数据后都成功了,但情况并非总是如此。 Thus people are advised to use the write-fdset for select() and poll() to check when the socket is writeable. 因此,建议人们对select()和poll()使用write-fdset来检查套接字何时可写。

How do usual mechanisms look like to actually buffer the data to send while still maintaining a well comprehensible sourcecode? 通常的机制在保持可理解的源代码的同时,看起来如何实际上缓冲要发送的数据?

I'm not deeply familiar with the *nix side of socket programming, but I encountered the same problem on Win32 side. 我对套接字编程的* nix方面并不十分熟悉,但是在Win32方面遇到了相同的问题。 Buffering is not so much of a problem (you queue the requests and peek on write completion to submit next from queue), the real problem is that the need to buffer signals that you're actually handling flow control and you cannot resolve flow-control with buffering alone: there can always be a consumer slower than the producer and the buffer will basically grow out of control. 缓冲并不是什么大问题(您将请求排入队列,并在写入完成后进行窥视以从队列中提交下一个),真正的问题是需要缓冲实际上正在处理流控制且无法解决流控制的信号仅使用缓冲:总是有一个消费者比生产者慢,并且缓冲基本上将失去控制。 You have to propagate the flow control up the stream to whatever module is producing the data, and this makes really complex interfaces. 您必须将流控制向上传播到生成数据的任何模块,这使接口变得非常复杂。 All 'write' requests must support return codes indicating flow control status (ie. 'stop writing, there is no more space!') and callbacks to invite the caller to resume write operations. 所有“写”请求必须支持指示流控制状态的返回码(即“停止写,没有更多空间!”)和回调,以邀请调用者恢复写操作。

As we're in C++ land, you could store the data in a std::vector 因为我们在C ++领域,所以可以将数据存储在std :: vector中

New data gets appended to the end of the vector. 新数据将附加到向量的末尾。 When you get notification that the socket is writable, try to send the complete vector. 当您收到套接字可写的通知时,请尝试发送完整的向量。 send() will return how much was really sent. send()将返回实际发送了多少。 Then simply erase that number of bytes from the beginning of the vector: 然后只需从向量的开头擦除该字节数即可:

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...
}

So there's probably more error checking to do, but you get the idea? 因此,可能还有更多错误检查要做,但是您明白了吗?

Rather queueing each individual send request, the advantage here is that you get to potentially combine multiple higher level sends into one socket send, assuming you're using TCP? 而不是对每个单独的发送请求进行排队,这样做的好处是,假设您正在使用TCP,则可以将多个更高级别的发送合并到一个套接字发送中。

But as Remus quite rightly mentions, your flow control and API is the tricky bit - ie how do you stop the buffer becoming too big? 但是正如Remus正确提到的那样,您的流控制和API有点棘手-即如何阻止缓冲区过大?

When writing OO that needs to center around a select()/poll() loop, you need a good abstraction. 在编写需要以select()/ poll()循环为中心的OO时,您需要一个良好的抽象。 I have always found the Adaptive Communications Environment (ACE) Reactor class very good for this. 我一直发现自适应通信环境(ACE)Reactor类对此非常有用。 There are a couple of books "C++ Network Programming" by Doug Schmidt that cover this environment also various other stuff on the web including The Design and Use of the ACE Reactor 道格·施密特(Doug Schmidt)撰写了两本书《 C ++网络编程》,涵盖了这种环境,并且网络上还有其他各种内容,包括《 ACE Reactor的设计和使用》。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM