自定义 Socket 接收 HTTP 请求,丢失请求体

2021-10-29 23:47:00 +08:00
 Lighthughjiajin

代码: https://github.com/qiujiajin/miniweb

Pycharm 打开项目 运行 examples/example1.py 启动服务 运行 test.py ,运行测试,可以看到 sync_requests(),同步情况下调用 requests 发送请求,解析正常; 调用 async_requests(),也就是多线程处理的时候,服务端 recv 接收数据时,会丢失请求体。

请教下大佬们,讲解一下,不甚感激~

2202 次点击
所在节点    Python
10 条回复
hsfzxjy
2021-10-30 00:43:04 +08:00
recv 不保证一次接收完,你要用一个循环读
yousabuk
2021-10-30 10:07:47 +08:00
接 1# 补充一个:

http 发的数据含 \r\n ,如果你接收按回车符判断接收完成,后边的就不读了,此时,你需要继续读就可以把后边的读出来。
vinle
2021-10-30 10:35:42 +08:00
前提条件:一般来说 server 都是一个请求对应一个进程。

1 )单线程的时候,客户端的全部 request 都是 blocking 的,即,每一个 request 的发送都基于上一个的 request-response 流程的成功完成,所以如果**服务器的处理逻辑正确**的情况下,你发了多少,server 就收到多少。

2 )对于楼主多线程的实现,在某一时刻 T1 ,可能出现这种情况:客户端所在的设备的网络接口( i.e. 网卡)会把 N 个 request 一起送出去,N>=1 。根据上述的前提条件,楼主的服务端(本质上就是个 httpserver )在下一时刻 T2 ,会对进来的流量进行处理(即,T1 时刻发的流量),然而同样,所以如果**服务器的处理逻辑正确**的情况下,server 会识别出有 N 个 req ,然后分别处理,所以有同样的结果:你发了多少,server 就收到多少。

综上,楼主说的 issue 和客户端线程是没关系的(必须的,不然电商怎么玩抢购),那问题实在哪里?就是上面写的正确的服务器处理逻辑。 很可惜的是这东西并不能靠改楼主的某一行代码就能解决问题(其实就是__init__.py, 144 ,加上楼上朋友的建议),因为正确的处理逻辑基于正确的了解“网络的属性”,如果没有后者,楼主的 WebServer()在未来某一时刻也同样会带来意想不到的结果。
Lighthughjiajin
2021-10-30 11:16:10 +08:00
Lighthughjiajin
2021-10-30 11:23:09 +08:00
@yousabuk 我是对于客户端的每次 TCP 连接,创建一个新的 socket 去服务,那么如果我用这个 socket 根据\r\n 过滤接收,那么我多余的数据没有接收,那部分数据会怎么处理的?
而且为什么每次丢失的都是请求体~
Lighthughjiajin
2021-10-30 11:38:20 +08:00
@vinle
我的实现是在一个进程里,开多个线程去处理新的 socket 连接。
但是呢,由于一个进程用一个端口号,那么所有客户端的连接发数据都是发送到这个端口号的。
我好奇每个线程里的 socket.recv ,都是到这个进程的接收缓冲区去拿的吗?
vinle
2021-10-30 14:28:29 +08:00
@Lighthughjiajin 刚刚我的描述可能有些偏差,纠正一下,前提条件那应该是“最基础的 server”。

“...发送到这个端口号的....” 即使你 N 个请求一起发送到给定的端口号,数据也不是聚在一起的,所以不存在单一的“进程的接收缓冲区”。事实是,一个 socket 对应一个连接,你指的 N 个线程里的 socket.recv ,那便是到这个 N 个连接对应的 N 个 socket 的对应的 connection 的所对应的缓冲区里边去拿。有点绕,其实就是 socket-conn-buffer 一一对应的意思。

Ref. https://en.wikipedia.org/wiki/Berkeley_sockets#accept
Lighthughjiajin
2021-10-30 14:49:14 +08:00
我发现请求有时候是先发送请求行和首部,然后再发送请求体。
所以我先解析出请求行和首部,然后判断 Content-Length: 来判断需要目前 body 是否接收完全,如果没接收完全的话,再次调用 recv 来接收,就解决了。
muzuiget
2021-10-30 20:50:59 +08:00
@Lighthughjiajin HTTP 的那个 Content-Length 本来的作用就是如此,你这个做法就是对的。

至少目前楼主没有说出两字禁言。
julyclyde
2021-11-01 11:45:34 +08:00

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/811647

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX