agent TCP read

12 篇文章 0 订阅
7 篇文章 0 订阅

这两天解除了网络模型,踩了一些坑, 现在写一点惨痛教训。
TCP 才read的时候,可能有这几种情况

1.       返回值>0,这种情况又分为2中情况

           1.1  返回值==想要读到的size,这种情况意味着这次读工作良好, 且读到了想要的byte数,在处理的时候,不要标记该连接的状态,继续下次read
           1.2  返回值 < 想要读到的size,这种情况意味着TCP接收缓冲区内的数据已经读完,我们在处理的时候,要标记该连接的状态为not ready,这次读完就要去等下一个epoll了


2.   返回值== 0, 这种情况是对端做了close的操作,这时候,我们应用层也要做清空缓冲区的操作。
3.      返回值 <0 , 这种情况下是遇到了错误,错误分为以下几种:
         3.1 errno == EINTR , 这种是遭遇中断,应该continue,继续read.   
         3.2 errno == EAGAIN || EWOULDBLOCK , 这种是读完了,其操作应该类似上面< 想要的size
         3.3 其他错误,是该连接出错,应该断连接

agent 代码

ssize_t conn_recv(struct conn *conn, void *buf, size_t size) {
                 ssize_t n;
                 ASSERT(buf != NULL);
                 ASSERT(size > 0);
                 ASSERT(conn ->flag & RECV_READY);
                 for (;;) {
                          n = da_read(conn ->fd, buf, size); // read 函数
                          log_debug("recv on fd %d %zd of %zu" , conn->fd, n, size);
                          if (n > 0) { //返回值大于0
                                 if (n < (ssize_t ) size) {//返回值小于size,这次epoll的数据都已经读完
                                     conn->flag &= ~RECV_READY ;// 置这个连接为不ready
                                     }
                                 conn->recv_bytes += (size_t ) n; // 等于size,epoll数据可能没读完
                                 return n;
                                }
                                 if (n == 0) {// 返回值等于零,对端关连接
                                       conn->flag &= ~RECV_READY ;
                                       conn->eof = 1;//置连接状态为eof                                         
                                       return n;
                                }

                                 if (errno == EINTR) {//EINTR错误码,应该继续read
                                       log_debug("recv on sd %d not ready - eintr" , conn->fd);
                                       continue;
                                } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
                                                 conn->flag &= ~RECV_READY ;                                            
                                                 return -2;
                                } else {
                                                 conn->flag &= ~RECV_READY ;
                                                 conn->error = 1;
                                                 conn->err = CONN_RECV_ERR ;                                                                                                            
                                                 return -1;
                                }
                }

                 return -1;
}
做了一些项目,开始对网络框架有了一些新的理解,然后重新阅读agent的代码,有了一些新的理解, 记下来,以免忘记

首先呢, 在agent建立了连接之后,就新建了一个conn 类型的结构体对象,然后把这个conn注册到epoll的响应事件中去。

在epoll_wait 响应的时候,我们可以通过epoll_event结构体的data.ptr成员可以获取得到这个响应的conn是哪个。

读和写类似, 所以本文着重讲read的过程:

那么在获得这个conn的读事件响应之后,agent是怎么做的呢?

首先给这个连接置一个flag 叫 RECV_READY,表示当前的连接可以读
  1. 然后conn当中维护了一个msg结构体叫rmsg,表示该连接接收的msg,如果rmsg为空,则新分配空间,然后返回rmsg进行处理

    msg结构体中也维护了一个buf的队列,一个buf结构体保存了实际收到的数据,从msg获取得到队列的最后一个buf,如果buf为空,或者最后一个buf也是满的就新建一个buf,插在msg结构体的尾部,然后把msg的pos指向buf的pos

    然后接收数据了,根据最后buf可以放的下的大小,定义read系统调用的最后一个参数,read之后返回值的具体处理看前面一篇文章,

    read返回的状态有4种,
    连接状态还是ready,那么就是从msg_pos开始继续做逻辑,然后从上述的1步骤,继续下一轮循环
    连接状态不ready,那么就做逻辑,然后这个conn的处理就结束了,不再下一轮循环
    conn->eof == 1,即收到read到的字节为0,那么就将conn里的msg清空
    conn->error == 1,即read的完之后为-1 ,且errno不为Intr 和 EAGAIN,那么则返回-1,然后做错误处理,清空连接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值