如何缓冲非阻塞 IO?
当我需要在阻塞文件描述符上缓冲 IO 时,我使用 stdio. 但是如果我根据手动将文件描述符转换为非阻塞模式,stdio 缓冲将无法使用。 经过一些研究,我发现 BIO 可用于缓冲非阻塞 IO。
但可能还有其他选择吗?
我需要这个以避免在多连接环境中使用线程。
When I need buffered IO on blocking file descriptor I use stdio. But if I turn file descriptor into non-blocking mode according to manual stdio buffering is unusable. After some research I see that BIO can be usable for buffering non-blocking IO.
But may be there are other alternatives?
I need this to avoid using threads in a multi-connection environment.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我认为你正在谈论的是反应堆模式。 这是一种无需线程即可处理大量网络连接的非常标准的方法,并且在多人游戏服务器引擎中非常常见。 另一个实现(在Python中)是扭曲矩阵。
基本算法是:
I think what you are talking about is the Reactor Pattern. This is a pretty standard way of processing lots of network connections without threads, and is very common in multiplayer game server engines. Another implementation (in python) is twisted matrix.
The basic algorith is:
我看到这个问题现在已经被编辑了,至少比以前更容易理解了。
无论如何,这不是一个矛盾吗?
同时做这两件事似乎是矛盾的,很难想象。
您追求的语义是什么? 如果您这样做:
如果有 3 个字节可用,您期望什么行为? 阻塞/缓冲 I/O 可能会阻塞,直到能够读取更多内容以满足您的请求,非阻塞 I/O 将立即返回 3 个可用字节。
当然,如果你有一些协议在上面,它定义了某种消息结构,这样你就可以知道“这个I/O不完整,我无法解析它,直到我有更多数据”,你可以自己缓冲它在该级别上,并且在收到完整消息之前不会向上传递数据。
I see the question has been edited now, and is at least more understandable than before.
Anyway, isn't this a contradiction?
Doing them both at the same time seems like a contradiction, and is hard to imagine.
What are the semantics you're after? If you do this:
What behavior do you expect if there is 3 bytes available? Blocking/buffered I/O might block until able to read more satisfy your request, non-blocking I/O would return the 3 available bytes immediately.
Of course, if you have some protocol on top, that defines some kind of message structure so that you can know that "this I/O is incomplete, I can't parse it until I have more data", you can buffer it yourself at that level, and not pass data on upwards until a full message has been received.
根据协议的不同,您当然可能需要缓冲非阻塞网络节点(客户端或服务器)的读取。
通常,这些缓冲区提供多个索引(偏移量),它们都记录最后处理的字节和读取的最后一个字节的位置(与处理的偏移量相同或大于处理的偏移量)。 而且它们还(应该)提供更丰富的压缩缓冲区语义、透明缓冲区大小管理等。
在 Java 中(至少),非阻塞网络 io (NIO) 包还提供了一组数据结构(ByteBuffer 等)旨在提供通用数据结构。
要么存在这样的 C 数据结构,要么您必须推出自己的数据结构。 一旦你拥有它,然后只需读取尽可能多的可用数据,让缓冲区管理溢出等问题(例如跨消息帧边界读取字节),并使用标记偏移量来标记已处理的字节。
正如 Android 所指出的,您(很可能)需要为每个打开的连接创建匹配的缓冲区。
Depending on the protocol, it is certainly possible that you will need to buffer your reads for a non-blocking network node (client or server).
Typically, these buffers provide multiple indexes (offsets) that both record the position of the last byte processed and last byte read (which is either the same or greater than the processed offset). And they also (should) provide richer semantics of compacting the buffer, transparent buffer size management, etc.
In Java (at least) the non-blocking network io (NIO) packages also provide a set of data structures (ByteBuffer, etc.) that are geared towards providing a general data structure.
There either exists such data structures for C, or you must roll your own. Once you have it, then simply read as much data as available and let the buffer manage issues such as overflow (e.g. reading bytes across message frame boundaries) and use the marker offset to mark off the bytes that you have processed.
As Android pointed out, you will (very likely) need to create matched buffers for each open connection.
您可以为每个打开的文件描述符创建一个包含缓冲区的结构,然后累积这些缓冲区,直到 recv() 返回 0 或者您的缓冲区中有足够的数据可以处理。
如果我正确理解你的问题,你不能缓冲,因为在非阻塞的情况下,你正在使用多个连接(如果是全局的)写入同一个缓冲区,或者只是写入小块数据(如果是本地的)。
无论如何,您的程序必须能够识别数据来自何处(可能通过文件描述符)并相应地对其进行缓冲。
线程也是一种选择,它并不像许多人听起来那么可怕。
You could create a struct with buffers for each open file descriptor, then accumulate these buffers until recv() returns 0 or you have data enough to process in your buffer.
If I understand your question correctly, you can't buffer because with non-blocking you're writing to the same buffer with multiple connections (if global) or just writing small pieces of data (if local).
In any case, your program has to be able to identify where the data is coming (possibly by file descriptor) from and buffer it accordingly.
Threading is also an option, it's not as scary as many make it sound out to be.
Ryan Dahl 的 evcom 库 正是您想要的。
我在工作中使用它并且效果很好。 但请注意,它(目前)还没有异步 DNS 解析。 Ryan 建议使用Michael Tokarev 的udns。 我现在正在尝试采用 udns 而不是阻止 getaddrinfo() 。
Ryan Dahl's evcom library which does exactly what you wanted.
I use it in my job and it works great. Be aware, though, that it doesn't (yet, but coming soon) have async DNS resolving. Ryan suggests udns by Michael Tokarev for that. I'm trying to adopt udns instead of blocking getaddrinfo() now.