C getline функция не читает строки как указано - PullRequest
1 голос
/ 26 ноября 2011

Мне нужно getline(), чтобы прочитать заголовок запроса, отправленный моим браузером на веб-сервер, который я программирую.Это функция getMessage, которая должна выполнять эту задачу:

char *getMessage(int fd) {
  FILE *sstream = fdopen(fd, "r");
  // initialise block to 1 char and set it to null
  char *block = malloc(sizeof(char));
  *block = '\0';
  int size = 1;

  // Read from the file descriptor fd (using a FILE stream) until a blank line is
  // received.
  // Read 100 lines (buffersize) from sstream and put into the buffer. If lines have
  // been successfully read concatenate them with block.
  int buffersize = 100;
  char *buffer = malloc (buffersize + 1);

  while(getline(&buffer,&buffersize,sstream) != -1){
     int length = strlen(buffer);
     printf("Buffer length: %d\n",length);
     block = realloc(block,strlen(block)+strlen(buffer)+1);
     strcat(block,buffer);
     if(strcmp(buffer,"\r\n") == 0) break;
 }

  int len = strlen(block);
  printf("Block length: %d\n", len);
  printf("%s \n", block);
  return block;
} 

По сути, вход функции getMessage (fd) является входом из моего прослушивающего сокета, объявленного в моем методе main.Я проверил, что вывод правильный.Теперь мне нужно преобразовать вывод из файлового дескриптора в строку и вернуть эту строку.Но каждый раз, когда я запускаю свой сервер, он застревает в цикле while.Не выполняются операторы в цикле.РЕДАКТИРОВАТЬ: Добавлено условие завершения цикла: теперь он сразу переходит к «Длина блока».Помощь очень ценится!

Ответы [ 2 ]

5 голосов
/ 26 ноября 2011
char buffer = (char *) malloc (buffersize + 1);

должно быть:

char *buffer = malloc (buffersize + 1);
5 голосов
/ 26 ноября 2011

Если вы используете функцию POSIX 2008 getline(), то вы выбрасываете полезную информацию (она возвращает длину строки, которую читает, поэтому, если вы захватите эту информацию, вы не захотите нужен strlen() в цикле.

Если код блокирует вызов getline(), это, вероятно, означает, что восходящий сокет не закрыт, но данные больше не отправляются. Ваш отправляющий код должен закрыть сокет, чтобы этот код мог обнаружить EOF.

Или, поскольку вы обсуждаете «пустую строку», то, возможно, ваш код должен проверять строку, содержащую только \r\n (или, может быть, просто \n) и прерывать цикл; ваш код не делает этого в данный момент.

Ваш цикл также имеет квадратичное поведение, поскольку вы постоянно используете strcat(). Лучше держать вкладки в конце строки и просто strcpy() новые данные после старых, а затем настроить указатель на конец строки.


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

Полезное правило : если вы выделяете ресурс, вы должны освободить его или передать обратно для освобождения.

Я рекомендую изменить интерфейс на использование уже открытого FILE * и ввести fdopen() в вызывающем коде. В качестве альтернативы, если вам больше не понадобится дескриптор файла, вы можете сохранить текущий интерфейс и использовать fclose() перед возвратом, но это также закроет базовый дескриптор файла.

Этот код работает для меня (MacOS X 10.7.2; XCode 4.2.1):

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

extern char *getMessage(FILE *);

char *getMessage(FILE *fp)
{
    char    *block = 0;
    size_t   size = 0;
    size_t   buffersize = 0;
    char    *buffer = 0;
    ssize_t  newlen;

    while ((newlen = getline(&buffer, &buffersize, fp)) > 0)
    {
        printf("Buffer length: %ld\n", (long)newlen);
        block = realloc(block, size + newlen + 1);
        strcat(&block[size], buffer);
        size += newlen;
        if (strcmp(buffer, "\r\n") == 0)
            break;
    }

    printf("Block length: %zd\n", size);
    if (size > 0)
        printf("<<%s>>\n", block);
    return block;
}

int main(void)
{
    char *msg;
    while ((msg = getMessage(stdin)) != 0)
    {
        printf("Double check: <<%s>>\n", msg);
        free(msg);
    }
    return 0;
}

Я протестировал его с файлом с окончанием строки в стиле DOS в качестве стандартного ввода, с пустой строкой в ​​качестве последней строки и с непустой строкой. Две пустые строки подряд тоже вроде бы были в порядке.

...