开发者社区> 问答> 正文

linux c:这个代码有什么问题?行读取和缓冲读取:报错

我在做web 上传,HTTP协议是基于文本行的。所以我原先的做法是写了一个不带缓冲的readline去每次读取HTTP数据包,效率低下的同时,部分文件上传还会损坏。之后更改为带缓冲的readline 将数据存入缓冲区之后再在缓冲区中readline。发现还是会有同样的问题。于是我测试了用带缓冲和不带缓冲的readline在本机上进行拷贝文件测试发现部分文件损坏,但文件副本之间的sha1值都相同。(部分文件损坏是指通过web上传会损坏的本地拷贝照样会损坏且哈希值是一样的)。之后用readn函数即从文件描述符中读取n个字符的函数发现拷贝是成功的。为什么会这样?
我之后测试了《unix网络编程》提供的带缓冲和不带缓冲的readline函数在本机上测试。通过web上传会损坏的文件拷贝照样会损坏。下面的readline代码来自《unix网络编程》:下面的readline拷贝文件会损坏

static int read_cnt;
static char *read_ptr;
static char read_buf[MAXLINE];

static ssize_t
my_read(int fd,char *ptr)
{
    if(read_cnt <= 0)
    {
again:
        if((read_cnt = read(fd,read_buf,sizeof(read_buf))) < 0)
        {
            if (errno == EINTR)
                goto again;
            return (-1);
        }else if(read_cnt == 0)
            return (0);
        read_ptr = read_buf;
    }

    read_cnt --;
    *ptr = *read_ptr ++;
    return 1;
}

ssize_t r_readline(int fd,void *vptr,size_t maxlen)
{
    ssize_t n,rc;
    char c,*ptr;
    ptr  = vptr;
    for ( n = 1;n < maxlen;n++)
    {
        if((rc = my_read(fd,&c)) == 1)
        {
            *ptr ++ = c;
            if (c == '\n')
                break;
        } else if(rc == 0)
        {
            *ptr =0;
            return (n-1);
        } else
            return (-1);
    }
    *ptr = 0;
    return (n);
}

readn函数

ssize_t readn(int fd,void *vptr,size_t n)
{
    size_t nleft;
    ssize_t nread;
    char *ptr;
    ptr = vptr;
    nleft = n;
    while(nleft > 0)
    {
        if ((nread = read(fd,ptr,nleft)) < 0)
        {
            if (errno == EINTR)
            {
                nread = 0;
            }
            else
                return -1;
        }
        else if(nread ==0)
            break;
        nleft -= nread;
        ptr += nread;
    }
    return (n - nleft);
}

谁能解释下为什么readline会失败?HTTP协议分析必须readline,真让人纠结 @中山野鬼 @osc所有人
环境:Linux pyplus-PC.lan 3.9.6-200.fc18.x86_64 #1 SMP Thu Jun 13 18:56:55 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
gcc:gcc (GCC) 4.7.2 20121109 (Red Hat 4.7.2-8)

展开
收起
kun坤 2020-06-07 22:32:57 611 0
1 条回答
写回答
取消 提交回答
  • UNP里面的这个readline确实没看太懂,所以我试验用的是CSAPP里面写的RIO######

    引用来自“Zirconi”的答案

    UNP里面的这个readline确实没看太懂,所以我试验用的是CSAPP里面写的RIO
    我现在碰到的问题是按行读取会有问题,但是HTTP协议是基于文本行的。所以我想问的是什么原因造成按行读取部分文件是会损坏
    ######谁把我题目給改了######仔细看了一下问题,似乎没看太懂?意思是损坏的文件SHA1值和好的是一样的?确定?######回复 @Zirconi : 你再仔细看下,我说的是文件副本之间的sha1值是一样的,那当然说的是对一个文件进行多次拷贝生成的副本 和web上传上来的损坏的副本sha1值是一样的。web服务器是我用c语言写的。目前需要添加上传文件功能######

    my_read 不要这么读。而是一次读取尽可能多的数据。如果一定要行才结束,就检测新读的数据是否存在\n。

    你这样读,my_read数据,如果在已经读了一些数据后,而出现errno,会导致你前面读取的数据丢弃。核心的原因是,你一次r_readline会触发多次my_read,而当最后一次my_read出现-1的情况,会把你前面几次正确读的数据给丢弃掉。

    你的代码有几个地方书写有问题。

    我不知道你这个代码是抄的还是自己写,自己写的都还好,抄的就有点郁闷了。

    另外最近我在写书中,也反复提到goto的用法,主要是鼓励用,但上面的情况不该用。下面我给个随手写的代码,没测试过。你可以试一下,至少逻辑主线按照你的思路,有点小区别。

    static int read_cnt = 0;
    static read_buf[MAXLINE];
    static char *read_ptr = read_buf;
    static int get_read_buf(int fd){
         int er = 0;
         read_ptr = read_buf;
          while ((read_cnt = read(fd,read_buf,sizeof(read_buf)) < 0){
                  er = errno;
                  if (er != EINTR) {
                     return 1; 
                  }
          }
           return 0 ;
          
    }
    static ssize_t my_read(int fd,char *ptr){
        if (read_cnt <= 0){
             if (get_read_buf(fd)){
                  return 0;
             }
        }
        if (read_cnt > 0){
              *ptr = *read_ptr ++;
               read_cnt--;
               return 1;
        } 
        return 0;
    }
    
    ssizt_t r_readline(int fd ,void *vptr,size_t maxlen){
         int i = 0;
          while (my_read(fd,vptr+i)){
                if (vptr[i] == '\n'){
                    i++;
                    break;
                }
                i++;
               if (i >= maxlen - 1) break;
    
         }       
         ptr[i] = 0;
          return i-1;
    
    }

    你对比下中间不一样的地方。 另外,如果你非要用char c这个空间的话,建议你如下申请和使用。

    char c[1];

     myread(fd,c);

    好处多多,比较容易把各种新手的错误浮现出来。

    另外这年头不流行*p++这种写法了。。上面保留了一个,我自己写,绝对不会这么做。

    另外补充,好的代码殊路同归,差的代码千奇百怪。说句狂的话,我3分钟看不懂的代码逻辑,基本是shit。即便linux内核,任何一个函数内部的逻辑你是容易看懂的,看不懂的是数据的来龙去脉和整体的目的性,但那些不属于代码逻辑。

    2020-06-07 22:33:03
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
Alibaba Cloud Linux 3 发布 立即下载
ECS系统指南之Linux系统诊断 立即下载
ECS运维指南 之 Linux系统诊断 立即下载