【问题标题】:C getline function not reading lines as specifiedC getline 函数未按指定读取行
【发布时间】:2011-11-26 18:00:29
【问题描述】:

我需要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 循环中。不执行循环中的语句。 编辑:添加了一个循环终止条件:现在它立即跳转到“块长度”。 非常感谢您的帮助!

【问题讨论】:

    标签: c webserver httprequest getline


    【解决方案1】:

    如果您使用的是 POSIX 2008 getline() 函数,那么您将丢弃有用的信息(它返回它读取的行的长度,因此如果您捕获该信息,则不需要 strlen() in循环。

    如果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 风格的行结尾作为标准输入的文件对其进行了测试,其中空行作为最后一行,非空行。连续两个空行似乎也可以。

    【讨论】:

    • Hi 添加了 strcmp 语句以跳出循环。还是没有变化!是的,正如您所说,规范说一旦我收到 \r\n - 传输结束就停止阅读。但即使添加 break 也不会改变。没有循环中断,结果我得到“块长度:0”。
    • @codaddict 指出的问题也是有效的——你的编译器应该毫不含糊地告诉你。如果不是,则说明您打开的警告不够多。
    • 呃!我注意到realloc() 代码中有space = realloc(space, new_size) 内存泄漏反模式,并且没有错误检查。重复的strcat() 是次优的(导致二次行为)。我应该找到写这篇文章的人并让他们修复它……哦……好吧,我应该修复它。它适用于玩具样品,没有错误。
    【解决方案2】:
    char buffer = (char *) malloc (buffersize + 1);
    

    应该是:

    char *buffer = malloc (buffersize + 1);
    

    【讨论】:

    猜你喜欢
    • 2015-06-05
    • 2019-11-26
    • 2023-03-24
    • 2012-10-02
    • 2021-12-05
    • 2022-07-02
    • 2012-09-21
    • 2013-11-30
    • 1970-01-01
    相关资源
    最近更新 更多