
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 如果需要长度可保证的传输请用 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 |