Надежно расщепляет линии из строки - PullRequest
1 голос
/ 11 марта 2010

Я пишу себе небольшой серверный демон на C, а основные компоненты, такие как обработка, подключаются, отключаются и получают уже, но проблема с получением по-прежнему сохраняется.

Я использую «recv» для чтения 256 байтов одновременно в массив символов, и, поскольку он может содержать несколько строк данных в виде одного большого блока, мне нужно иметь возможность разделять каждую строку отдельно для обработки. Это само по себе не было бы проблемой, но из-за возможности того, что строка могла быть обрезана, потому что она больше не помещалась в буфер, я также должен иметь возможность видеть, была ли линия обрезана. Не так уж и плохо, просто проверьте последний символ для \r или \n, но что за , если линия была обрезана? Мой код не позволяет легко «просто читать больше данных», потому что я использую select() для обработки нескольких запросов.

По сути, это моя ситуация:

//This is the chunk of code ran after select(), when a socket
//has readable data
char buf[256] = { 0 };
int nbytes;

if ((nbytes = recv(i, buf, sizeof(buf) - 1, 0)) <= 0)
{   
   if (nbytes == 0)
   {   
      struct remote_address addr;

      get_peername(i, &addr);
      do_log("[Socket #%d] %s:%d disconnected", i, addr.ip, addr.port);
   }   
   else
      do_log("recv(): %s", strerror(errno));

   close(i);
   FD_CLR(i, &clients);
}   
else
{   
   buf[sizeof(buf) - 1] = 0;
   struct remote_address addr;

   get_peername(i, &addr);
   do_log("[Socket #%d] %s:%d (%d bytes): %s", i, addr.ip, addr.port, nbytes, buf);

   // split "buf" here, and process each line
   // but how to be able to get the rest of a possibly cut off line
   // in case it did not fit into the 256 byte buffer?
}

Я думал о том, чтобы иметь временную буферную переменную с более высокой областью действия (возможно, malloc() 'd), чтобы сохранить текущий буфер, если он был слишком длинным, чтобы соответствовать сразу, но я всегда чувствую себя плохо из-за введения излишне высокой области переменные, если есть лучшее решение: /

Я ценю любые указатели (, кроме XKCD :)) )!

Ответы [ 2 ]

3 голосов
/ 11 марта 2010

Полагаю, вам нужно добавить еще один буфер для каждого потока, который содержит неполную строку, пока не будет получен перевод строки, следующий за ней.

0 голосов
/ 11 марта 2010

Я бы использовал какой-то динамически расширяемый буфер, например GString , для накопления данных.

Другая вещь, которая может помочь, - перевод сокета в неблокирующий режим с использованием fcntl(). Тогда вы можете recv() в цикле, пока не получите -1. Проверьте errno, это будет либо EAGAIN, либо EWOULDBLOCK (и они не обязательно должны иметь одно и то же значение: проверьте оба).

Последнее замечание: я обнаружил, что использовать libev (Google; я не могу опубликовать несколько ссылок) было веселее, чем select().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...