Есть TCP соединение (т.е. поток байтов), из него эти байты читаются и разбиваются на сообщения-пакеты определённого протокола уровня приложения. Каждое сообщение имеет либо фиксированный заранее известный размер, либо в заголовке содержит длину. Максимальный размер пакета - N, заранее известен и ограничен.
Варианты реализации: 1) Пишем байты из сокета в буфер размером N, когда в буфере оказывается целое сообщение, вызываем функцию-обработчик этого сообщения. Недостатки - нужно целое сообщение в буфере. Допустим, в буфер пришло сообщение размером N/2, за ним сообщение размером N, но оно уже в буфер целиком не влазит. Поэтому, после обработки первого сообщения затираем его и перемещаем первый кусок следующего сообщения к началу буфера, используя memmove(). Затем читаем из сокета до победного конца. Мне здесь не нравится наличие memmove()
|----message1---||---mesage2--
0 N
2) Выделяем буфер размером 2N. Читаем из сокета не больше N байт за раз. Если буфер заполняется на N или больше, читаем из сокета ровно столько, чтобы прочитать хвост последнего сообщения, размер хвоста известен из уже пришедшего заголовка. После этого пишем в буфер с начала. Здесь мне не нравится то, что recv() возможно придётся дёргать чаще мелкими порциями. Но вариант кажется оптимальным.
|----message1---||---mesage2----------|---------------
0 N 2N
3) Допускаем, что функции-обработчику не нужно целое сообщение в буфере, функция может хранить состояние и парсить сообщение по кусочкам, по мере прихода. Здесь недостаток в том, что поля сообщения придётся по байтам или по кусочкам копировать в отдельные буфера. Потому что в буфере чтения оно может не быть представлено в целом виде. В первых двух вариантах можно просто передавать указатели на поля внутри буфера чтения.
Что анонимный разум имеет сказать по этому поводу? Есть идеи|алгоритмы получше?