libevent源码分析-修改read回调每次最大只能获取到4096字节的限制

博客分析了libevent在处理大报文时,为何每次read回调只能获取4096字节的原因,涉及TCP拆包、socket缓冲区大小及libevent自身的限制。提出了修改socket缓冲区大小和libevent源码的方法,包括调整EVBUFFER_MAX_READ宏定义和bufev_p结构体初始化中的readmax值。
摘要由CSDN通过智能技术生成


背景
  有次在处理一个客户需求时,需要我这里开一个tcp的服务端,然后对方将图片进行base64编码后发送过来,由于图片比较大,再加上base64编码,结果导致整个报文长度达到1500KB,然后我用libevent进行接收的时候,我原以为进入回调后可以直接从evbuffer中将这1500KB的报文一次性获取出来,但事实不是这样的,进入回调后只能获取到2920字节的报文,然后我判断长度不对,直接return,神奇的是这次获取到了7016Byte,比上一次进入回调多了4096字节,然后再return它又会再次进入回调,这次又会比上次能多获取到4096字节,以此类推,对方只发送了一个1500KB的报文,我这里一共反复进了300多次回调才把整个报文接收完成(1500KB接收完成了就不会再进入回调了)。

 现在有两个问题:
1,为什么第一次进入回调只能接收到2920字节?
2,为什么每次进入回调只能比上次多获取4096字节,不能一次性全获取出来吗?

对于第一个问题,我用wireshark抓包发现,由于1500KB的报文太大,对方发送过来的时候TCP底层已经对这个1500KB的报文进行了拆包发送处理,刚刚好第一个包的大小就是2920字节,这时候libevent检测到有数据后就第一时间进入了read回调,而且进入回调后我获取当前socket缓冲区可读的字节大小时发现居然是0,也就是说这2920字节发送过来后libevent就第一时间将这些数据从socket缓冲区读取出来并放到evbuffer中然后立即进入了read回调(我是在进入read回调的第一行代码就是获取当前socket缓冲区的可读字节数,代码如下),然后再次进入回调的时候libevent又从缓冲区读取了4096字节出来放到evbuffer中,这时候我再获取socket缓冲区可读字节数的时候发现是8192字节,这说明socket缓冲区的默认大小是8KB。

  #define EVBUFFER_MAX_READ 40960
  //获取当前socket缓冲区有多少字节数据,入参是socket连接描述符
  static int get_n_bytes_readable_on_socket(evutil_socket_t fd)
  {
   unsigned long lng = EVBUFFER_MAX_READ;
   if (ioctlsocket(fd, FIONREAD, &lng) < 0)
    return -1;
   return (int)lng;
  }

梳理的过程如下:
→客户端发送1500KB报文
→客户端的TCP底层拆包发送
→服务端获取到第一个包大小时2920字节
→libevent获取到2920字节并进入read回调(此时不把这2920字节数据取出来,直接return,让数据还保存在evbuffer中)
→libevent再从socket缓冲区获取4096字节并进入回调(此时还有1400多KB的数据不知道存在哪里,反正不在socket缓冲区里面,因为socket缓冲区默认只有8KB)
→libevent从缓冲区取出4096字节后,缓冲区有了4KB的空闲空间,这时候TCP底层又往缓冲区里面放了4KB数据
→libevent再从缓冲区取出4KB放到evbuffer并进入回调,TCP底层又再往缓冲区放KB
→以此类推,直到libevent把这1500KB的数据全取出来放到evbuffer中。

分析到这里就发现限制每次进入回调获取数据长度只能是4096字节的原因有两个:
1,socket缓冲区的大小,默认只有8KB。
2,libevent自身只能最大获取4096字节,估计libevent源码里面限制了,要修改libevent源码。

修改socket缓冲区大小简单,只要在libevent的accept回调里面设置就行了,代码如下

	int nRecvBufLen = 128 * 1024; //设置为K
	setsockopt( fd, SOL_SOCKET, SO_RCVBUF, ( const char* )&nRecvBufLen, sizeof( int ) ); 

那么如何修改libevent源码呢?
首先必须要直到libevent接收到数据后的处理流程,如下
TCP底层接收数据→调用evbuffer_read来从缓冲区读取数据→进入read回调。需要说明的是evbuffer_read函数的调用时libevent自己调用了,我们是不管的,我们只

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值