tags:

views:

306

answers:

6

How can I tell if a read socket buffer is full or a write socket buffer is empty?

Is there a way I can get the status of a socket buffer without a system call?

UPDATE: How about this: I'd like to get a callback or signal when either the read socket buffer is full or the write socket buffer is empty. This way I can stop processing to allow more I/O to occur on the wire, since being I/O bound is always an issue when sending data on the wire.

The select() call is how you check if the read buffer has something in it. Not when it is full (I think).

+1  A: 

Taking in account that the kernel buffer for sockets lives in kernelspace I doubt there is any way of asking for the size without a syscall.
With syscalls you can try recv with PEEK.

ret = recv(fd, buf, len, MSG_PEEK);

Will give do the recv but without emptying the buffer.

Arkaitz Jimenez
yeah... thats something I hadn't thought of. I was just hoping I could get a kernel callback or signal to let me know the buffer was fukll.
Crazy Chenz
+2  A: 

That is not possible without a syscall. But what's the problem with syscalls?

Johannes Weiß
(I think) they are slower than shared memory or callbacks.
Crazy Chenz
they have some overhead since they have to switch to kernel mode and back but it is simply not possible to do anything like that without syscalls...
Johannes Weiß
+3  A: 

Poll the file descriptor with select and a zero timeout - if select says it's writeable, the send buffer isn't full.

(Oh... without a system call. No, there isn't.)

Addendum:

In response to your updated question, you can use two ioctls on the TCP socket: SIOCINQ returns the amount of unread data in the recieve buffer, and SIOCOUTQ returns the amount of unsent data in the send queue. I don't believe there's any asynchronous event notification for these though, which will leave you having to poll.

caf
+1 for select (as for the oddness - there's got to be some reason behind. Now that reason would be very interesting to know indeed.)
Andrew Y
updated the question to clarify
Crazy Chenz
From my understanding select only lets me know when the send buffer is _not_ full and the read buffer is _not_ empty. I want to know when the read buffer is full and the send buffer is empty.
Crazy Chenz
A: 

Have you tried select()?

Mick Walker
updated the question
Crazy Chenz
+1  A: 

You can try ioctl. FIONREAD tells you how many bytes are immediately readable. If this is the same as the buffer size (which you might be able to retrieve and/or set with another icotl call), then the buffer is full. Likewise, if you can write as many bytes as the size of the output buffer, then the output buffer is empty.

I don't how widely supported FIONREAD, FIONWRITE, and SIOCGIFBUFS (or equivalents) are. I'm not sure I've ever used any of them, although I've a sneaky feeling I've used similar functionality on Symbian for some reason or other.

Whether the call needs kernel mode to compute this is platform-specific. Vaguely trying to avoid system calls is not a valid optimisation technique.

A basic BSD-style sockets interface doesn't say anything much about read and write buffers. When does it matter whether the send buffer is empty? It certainly doesn't mean that all the data has been received at the other endpoint of the socket - it could be sitting in some router somewhere. Likewise, "your" read buffer being full doesn't guarantee that a write at the other end will block.

Generally speaking, you just read/write as much as you can and let the sockets layer handle the complexity. If you're seeing a lot of I/O completed with tiny sizes then maybe there's some performance problem. But remember that a stream socket will send/receive a packet at a time, containing a block of data. Unless TCP_NODELAY is set, it's not as though bytes are arriving by ones at the NIC, and you might end up making one read call per byte. They're arriving in packets, so most likely will become readable all at once, perhaps 1k-ish at a time. You're unlikely to be able to speed things up by holding off reading until there's a lot to read. In fact you might make it worse, because by the time your endpoint's read buffer is full, there's a risk that incoming data is being discarded because there's nowhere to store it, resulting in delays and re-sends.

Steve Jessop
Makes sense.... Pointing out the fact that things are being transfered in packets (with IP traffic) does make the "problem" a moot point. Thanks for the advice.Chenz
Crazy Chenz
A: 

I think there's a fundamental reason why your approach is flawed/doomed. The system doesn't want to tell you when the read buffer is full / write buffer is empty because those events indicate a break down in the contract between you and the system. If things get to that point (particularly in the read direction) it is too late for you to ensure smooth operation of the protocol stack. Some more data might arrive while you are finally deciding to read the buffer. You should be reading the buffer before it gets full, that's the whole point of buffered I/O.

Bill Forster
eh... I just assume nothing in the digital world is smooth...especially under the covers. ;-) Thanks for the input though!
Crazy Chenz