views:

1254

answers:

5

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.

+4  A: 

I see the question has been edited now, and is at least more understandable than before.

Anyway, isn't this a contradiction?

  • You make I/O non-blocking because you want to be able to read small amounts quickly, typically sacrificing throughput for latency.
  • You make it buffered because you don't care that much about latency, but want to make efficient use of the I/O subsystem by trading latency for throughput.

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:

int     fd;
char    buf[1024];
ssize_t got;

fd = setup_non_blocking_io(...);
got = read(fd, buf, sizeof buf);

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.

unwind
doing this allow me avoid thread using in multi-connection application.
vitaly.v.ch
It's not a contradiction. Non-blocking I/O is most often used when the program needs to do other work (often servicing other descriptors) and does not want to block on any given descriptor. That's a somewhat different kind of latency than waiting for full buffers.
dwc
+13  A: 

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:

  • have a buffer for each socket
  • check which sockets are ready to read (select(), poll(), or just iterate)
  • for each socket:
    • call recv() and accumulate the contents into the socket's buffer until recv returns 0 or an error with EWOULDBLOCK
    • call application level data handler for the socket with the contents of the buffer
    • clear the socket's buffer
sean riley
In description of Reactor Pattern I found out libowfat. It's most adequate for my need from this thread. THANKS
vitaly.v.ch
A: 

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.

Andrioid
A: 

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.

A: 

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.

temoto