import socket
response = 'HTTP/1.1 200 OK\r\nConnection: Close\r\nContent-Length: 11\r\n\r\nHello World'
server = socket.socket()
server.bind(('0.0.0.0', 9527))
server.listen(1024)
while True:
client, clientaddr = server.accept() # blocking
request = client.recv(1024) # blocking
print request
client.send(response) # maybe blocking
client.close()
这个例子很简单,运行起来也没啥问题,但是我不明白 recv 这个函数是怎么判断客户端的数据都传过来了?比如客户端应该传 10B 的数据,先传了 5B ,然后隔了 1 秒,此时 recv 应该返回收到的 5B 数据,还是继续等,那要等到什么时候呢?
1
des 2016-04-10 17:29:34 +08:00 via Android
client.recv(len)
在接收到至少 len 字节的数据之前,造成一个阻塞,并暂停脚本运行( block )。但是, 如果接收到中断信号,或远程服务器断开连接,该函数将返回少于 len 字节的数据。 |
2
magicdawn 2016-04-10 17:30:08 +08:00
timeout
|
3
Mutoo 2016-04-10 17:37:04 +08:00
tcp 协议有一个 push 标记,会让传输层立即把数据传给应用层,即使缓冲区未满。
|
4
anexplore 2016-04-10 18:08:42 +08:00 via iPhone
可以看一下这个 http://m.blog.csdn.net/article/details?id=7689409 ,在应用层则可以通过设置数据长度或者关闭 socket 等方法表示数据接收完毕
|
5
micyng 2016-04-10 18:33:53 +08:00 via Android
如果是阻塞模式,就一直读
|
6
gamexg 2016-04-10 19:43:06 +08:00
不会等待,而是直接返回 5B 数据。
recv 意思是接受不超过 len 长度的数据。一般在阻塞模式下必须收到数据才返回,但是不在意到底收到了多少数据,也就是返回的数据可以不够 len 长度。 在阻塞模式下除非远端关闭连接(包括关闭单个方向的连接)否则必定读到数据才返回。也就是如果 recv 返回的数据是空,那么表示连接断开了。 对了上面没考虑超时的问题。 |
7
mhycy 2016-04-10 19:46:37 +08:00 1
如果需要长度可保证的传输请用 UDP ,那是包协议(而 TCP 是流协议)
如果需要在 TCP 做包处理,请在此基础上实现长度判断以及异常处理 (例如发生拔网线之类不会产生任何提示的网络中断) |
8
gamexg 2016-04-10 19:47:44 +08:00
对了,还要注意 client.send ,这个函数返回已发送的字节数, python 不保证所有数据都发出去了。你需要自己检查是否都发出去了,如果没有那么需要继续通过 client.send 发送剩余的内容。可以换成 sendall 来解决。
|
9
bp0 2016-04-10 20:34:09 +08:00
通常都是在 TCP 之上增加应用层协议,先发送长度或者类似信息,然后再发送数据的。
就像 @mhycy 说的, TCP 是流协议不能保证你这边发送 5B 时对方会马上收到。有可能你连续发送 2 次 5B ,对方一次收到 10B 。 |
10
ayiis 2016-04-10 20:57:32 +08:00
如果楼主其实是想问 http 的话:
1. 读取 http 的 header 2. 解析 header 3.1 如果 Transfer-Encoding:chunked ,则需要按段读取,并把每段的段头和段尾删除 3.2 否则获取 Content-Length ,读到指定长度完毕(如果后面还有数据则截断 4. 配合超时 如果是 tcp 的话,我觉得 tcp 只有对方发送 FIN 或者 RST 之后才算结束,所以如果对方 SYN flood 你 |
11
ryanking8215 2016-04-11 08:55:34 +08:00
TCP 是流方式,有粘包和漏包的问题,所以一般协议里都需要同步头和数据长度等信息,让应用层来确定消息边界。
|
12
eightqueen OP @Mutoo 没错,就是 push ,谢谢
|
14
bp0 2016-04-13 10:29:35 +08:00
@mengzhuo 像楼主这种局域网的情况下,中间延迟 1s ,肯定是先收到一个 5b ,然后再收到另外一个 5b 。
但是,如果中间没有延迟 1s ,客户端连续调用两次发送 5b ,在客户端的 TCP 层就会被 Nagle 算法合并了,根本不需要合包的设备。 还有,如果是互联网,那么即使延迟 1s ,最终到达服务器的数据包也有可能已经被合并成 10b 的一包了。 |
15
ayiis 2016-04-16 23:46:40 +08:00
|