部分代码:
#平台限制,只能用 Python2.x 实现
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('0.0.0.0',80)
sock.listen(1)
下面是 recv 应该收到的完整数据(HTTP 请求):
POST /data/fetchdata HTTP/1.1
Host: www.demo.com
Accept: application/json
Accept-Encoding: gzip, deflate
Content-Length: 8
Cookie: debug=1
Connection: closed
result=1
一开始为了接收数据写的的代码:
buf=''
While True:
buf = buf + client.recv(1024)
if not buf or len(buf)==0:
break #结果是从来不 break
再试
buf = client.recv(4096)
这个只能收到一部分数据(HTTP response body 收不到)。这里有个问题,无论把 buffer 调整多大,第一次 recv 的返回值总是 HTTP response header 部分的数据,很奇怪
后来试了
buf = client.recv(1024) #成功接收 HTTP response header
print "123"
buf = client.recv(1024) #应该接收 HTTP response body,但是一直 blocking
print "456"
这样的,发现 456 根本不输出。
快速 Google 之后也没发现什么适合的解决方法,唯一一个靠谱点的是用 try except 配合自定义 timeout 来检测是否 blocking,缺点就是在网络环境比较恶劣的情况下(比如我现在的)也会丢数据。
向大家求教,谢谢!
1
neoblackcap 2018-09-17 17:38:29 +08:00 1
你自己不 parse 就想读出来? tcp 又不保证你一次就收到全部数据
|
2
userlol OP @neoblackcap 求教,循环执行 recv 收所有数据没关系,但是如果最后一次数据收空了,recv 就又进入等待状态了,这个怎么解决?
|
3
Tyanboot 2018-09-17 18:10:59 +08:00 via Android 1
@userlol 这就是流的处理问题了。HTTP 还行,可以读一部分就解析一部分,拿到 content-length 之后就立刻再算你还需要接受多少。
|
4
neoblackcap 2018-09-17 18:26:16 +08:00 via iPhone 1
@userlol 如 3 楼所说,你必须先循环读出头部,然后才按长度去读剩下的部分。
还有就是你读到尾部,也有可能是一部分尾部,一部分是另外一个请求,记得将他们分开 |
5
neoblackcap 2018-09-17 18:27:57 +08:00 via iPhone
而且你想性能好些应该用 epoll 来监听 socket 是否可读,用另外一个线程去读
|
6
sampeng 2018-09-17 18:28:04 +08:00
content-length 就是干这个用的。。。
|
7
miniliuke 2018-09-17 19:07:17 +08:00 via Android 1
http 应该是短链接( http2 除外,我不太了解),你循环读把数据拼接起来就行,直到服务器关闭连接结束......一般一次连接不会传两个 http 数据的......你直接读到 socket 关闭就行
|
8
misaka19000 2018-09-17 19:31:28 +08:00 1
最近刚刚用 go 写过一个程序,里面包含了对 HTTP 请求的简单解析,楼主可以参考下,Python 实现起来也差不多
https://gist.github.com/RitterHou/e77b38acdd30d30ee3b9f19004940d3c |
9
ysc3839 2018-09-17 20:06:34 +08:00 via Android 1
buf=''
While True: . recv = client.recv(1024) . if not recv or len(recv) == 0: . break . else: . buf += recv |
10
Jamy 2018-09-17 20:22:31 +08:00 1
>buf = client.recv(1024) #应该接收 HTTP response body,但是一直 blocking
>print "456" 这说明缓冲区里没数据了, 检查一下发送端是不是没发送完整. 需要注意下.send 方法可能会只发送部分数据,要自己检查返回值. |
11
pabupa 2018-09-17 20:40:01 +08:00 1
|
12
lcj2class 2018-09-17 20:50:37 +08:00 via Android 2
|
13
BingoXuan 2018-09-18 09:37:19 +08:00 via Android
tcp 又不保证你的数据能快速按顺序到达缓存区,所以一直接收直到识别到 eof 或特定结束符就可以了。我还遇过收数据收到前面一部分数据,后面死活收不了,一关闭就收到剩下的
|