NewLifeX / X

Core basic components: log (file / network), configuration (XML / JSON / HTTP), cache (memory / redis), network (TCP / UDP / HTTP), RPC framework, serialization (binary / XML / JSON), APM performance tracking. 核心基础组件,日志(文件/网络)、配置(XML/Json/Http)、缓存(内存/Redis)、网络(Tcp/Udp/Http)、RPC框架、序列化(Binary/XML/Json)、APM性能追踪。

Home Page:https://newlifex.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

http post在数据量大于8KB的时候会有问题

zhangzhui opened this issue · comments

vs:2019
.net framework: 4.0
newlife.core: 8.11.2021.809

用curl post一个大于8KB的文件,在IHttpHandler的ProcessRequest中保存为文件,保存的总是最后一个Packet的数据包。
例如:

  1. post一个16KB的文件
    第一个8KB第一个字节为0x31,其余为0x30
    第二个8KB第一个字节为0x32,其余为0x30
  2. 在IHttpHandler的ProcessRequest保存文件,文件内容全部为第二个8KB字节的数据,包含了2份,所以收到的文件大小相同
    image

附上一个测试文件,总共24KB
第一个8KB 0x31 0x30 ...
第二个8KB 0x32 0x30 ...
第三个8KB 0x33 0x30 ...
保存的话,保存三份0x33 0x30 ...
1.txt

commented

Packet就是对buffer的包装,以减少字节数组的内存拷贝,这个设计类似于.NET新出来的Span。
每次收到数据时,的确是利用Packet包装一下SAEA的buffer,并且上层协议解析,也是Packet的再次包装,完美避免多次内存拷贝。
但是问题也很明显,就是这个数据包不能送给别的线程使用,也不能“缓存”下来留给下一次使用。

8k大小的问题的确欠考虑,正在分析处理!
今天看到了邮件,网络原因不方便上来回复

commented

image

已修改。如果一个请求未完成,则克隆Body部分,后续每次收到数据包,都触发Body部分,直到完成,才会调用ProcessRequest

Packet就是对buffer的包装,以减少字节数组的内存拷贝,这个设计类似于.NET新出来的Span。
每次收到数据时,的确是利用Packet包装一下SAEA的buffer,并且上层协议解析,也是Packet的再次包装,完美避免多次内存拷贝。
但是问题也很明显,就是这个数据包不能送给别的线程使用,也不能“缓存”下来留给下一次使用。

8k大小的问题的确欠考虑,正在分析处理!
今天看到了邮件,网络原因不方便上来回复

我对您追求完美以及追求极致效率很是佩服
但是这里冒昧的说一句:适当的增加内存拷贝会让程序变的更容易理解,比如下面:
image

SAEA里的设置buffer应该是从内核里返回的数据,每次receive的时候都会用到这个buffer,而交给上层应用层去处理的时候是不是clone一份更容易理解一点?这样二者不容易混淆。

另外这个bug应该也是同样的问题,超过了8KB(默认大小),导致后面收到的数据覆盖掉了第一个8KB的Packet,导致解析数据包失败,没有通知给上层,您看呢?

image

已修改。如果一个请求未完成,则克隆Body部分,后续每次收到数据包,都触发Body部分,直到完成,才会调用ProcessRequest

您要是这么修改的话,Packet是不是要增加一个析构函数或者一个Dispose?不然会不会有内存泄漏?

commented

从2005年开始,这是我们第三代网络库,务必追求零拷贝ZeroCopy。尽管给上层带来了一点问题,但只要遵守独占缓冲区原则,离开本线程时拷贝,就不会有太大问题。
第三代网络库的吞吐压测峰值是2266万qps,这里的ZeroCopy就是最后一针推进剂。

嗯。了解了。
那是不是可以httpsession传递给IHttpHandler不必等所有的数据都ready,而是通过流的方式给IHttpHandler,所有业务层的数据由业务来处理。这样数据量小的业务8KB足够了,数据量大的话则自己处理。

commented

image
已修改。如果一个请求未完成,则克隆Body部分,后续每次收到数据包,都触发Body部分,直到完成,才会调用ProcessRequest

您要是这么修改的话,Packet是不是要增加一个析构函数或者一个Dispose?不然会不会有内存泄漏?

不需要dispose,我们用的是托管内存,gc会回收处理,不存在内存泄漏

commented

嗯。了解了。
那是不是可以httpsession传递给IHttpHandler不必等所有的数据都ready,而是通过流的方式给IHttpHandler,所有业务层的数据由业务来处理。这样数据量小的业务8KB足够了,数据量大的话则自己处理。

的确是这样,只是目前我还没有好的思路去调整这个数据流的用法,这么做最好的用途就是文件上传