4

I have an app that uses the civetweb (formerly mongoose) HTTP server library to create an MJPEG stream. Works fine when my MJPEG settings match the bandwidth profile of the network the clients are connecting from, but occasionally we have a low bandwidth connection that I'd like to accommodate by dropping frames.

Right now when I call mg_write(), the mongoose library calls send() like this:

send(sock, buf + sent, (size_t) k, MSG_NOSIGNAL);

What I'd like to do is check the outgoing buffer of the socket, and if it's full, skip a frame. Is there any way to check this at the application level?

EDIT: Just a side note for MJPEG folks, these TCP buffers are pretty large and what I actually ended up measuring was simply if there were any bytes present in the buffer at all. If there were more than zero I skipped a frame.

mpr
  • 3,250
  • 26
  • 44

2 Answers2

4

You can use ioctl for this on Linux (and similar interfaces on other systems):

#include <linux/sockios.h>

size_t sb_sz = sizeof(sock_buffer_size);
ioctl(sock, SIOCOUTQ, &bytes_in_queue);
getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sock_buffer_size, &sb_sz);
size_t bytes_available = sock_buffer_size - bytes_in_queue;

Note that it still does not give you 100% guarantee that the write will succeed in full, but it gives you pretty good chance of it.

mpr
  • 3,250
  • 26
  • 44
SergeyA
  • 61,605
  • 5
  • 78
  • 137
-1

What I'd like to do is check the outgoing buffer of the socket, and if it's full, skip a frame. Is there any way to check this at the application level?

Sure, call select() and see if the socket selects as ready-for-write. If it doesn't, that means the socket's outgoing buffer is full. (You can use select()'s timeout parameter to force the select() call to return immediately, if you don't want it to block until a socket is ready to read/write/etc)

Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234
  • Care to explain why not? – Jeremy Friesner Apr 21 '16 at 14:02
  • 1
    Because it gives you the indication that you can send at least a single byte. But OP doesn't need this, they need to know if they can sent the whole frame (and skip it otherwise). – SergeyA Apr 21 '16 at 14:36
  • The OS is pretty flexible about allowing writes to a TCP socket even when it's backing up, so it's true select() is not really sufficient for my needs here, though for other cases it may work. – mpr Apr 21 '16 at 14:53
  • It's sufficient with a bit of work: what I do is keep a FIFO queue of outgoing bytes that are ready to be sent to the socket, and whenever the sockets selects() as ready-for-write, I transfer as many bytes as possible from the FIFO queue to the socket. Whenever the FIFO queue is empty (and I have more data to send), I dump another frame of bytes to the FIFO queue. – Jeremy Friesner Apr 21 '16 at 18:07