原位置:http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/408859

Description:

An issue with socket.recv is how to know when you are done receiving data. A TCP stream guarantees the bytes will not arrive out of order or be sent more than once. But you do not know the size of the data that will be sent to you. 100 bytes could be sent as group of 10 bytes or maybe in one shot. Ultimately, this means you have to use a loop in some fashion until you know it is done.

The basic recv returns an empty string when the socket is disconnected.

From that you can build a simple loop that will work as long as the sender manages to disconnect the socket at the appropriate time. However, there could be situations where a local error will mask as a clean shutdown or maybe a close() is never called.

Three very basic methods are shown below that try to fix that problem. They use either a time-based, end marker, or size of payload method. Since you cannot be sure just what you are going to receive, you have to be careful that you get enough of a message to determine the size of payload or end marker.

I updated the recv_size method to allocate data in larger chunks if it gets a large stream of data, which can increase performance.

代码如下:

import socket,struct,sys,timePort=2222

#assume a socket disconnect (data returned is empty string) means all data was #done being sent.

def recv_basic(the_socket):

total_data=[]

while True:

data = the_socket.recv(8192)

if not data: break

total_data.append(data)

return ''.join(total_data)

def recv_timeout(the_socket,timeout=2):

the_socket.setblocking(0)

total_data=[];data='';begin=time.time()

while 1:

#if you got some data, then break after wait sec

if total_data and time.time()-begin>timeout:

break

#if you got no data at all, wait a little longer

elif time.time()-begin>timeout*2:

break

try:

data=the_socket.recv(8192)

if data:

total_data.append(data)

begin=time.time()

else:

time.sleep(0.1)

except:

pass

return ''.join(total_data)

End='something useable as an end marker'

def recv_end(the_socket):

total_data=[];data=''

while True:

data=the_socket.recv(8192)

if End in data:

total_data.append(data[:data.find(End)])

break

total_data.append(data)

if len(total_data)>1:

#check if end_of_data was split

last_pair=total_data[-2]+total_data[-1]

if End in last_pair:

total_data[-2]=last_pair[:last_pair.find(End)]

total_data.pop()

break

return ''.join(total_data)

def recv_size(the_socket):

#data length is packed into 4 bytes

total_len=0;total_data=[];size=sys.maxint

size_data=sock_data='';recv_size=8192

while total_len

sock_data=the_socket.recv(recv_size)

if not total_data:

if len(sock_data)>4:

size_data+=sock_data

size=struct.unpack('>i', size_data[:4])[0]

recv_size=size

if recv_size>524288:recv_size=524288

total_data.append(size_data[4:])

else:

size_data+=sock_data

else:

total_data.append(sock_data)

total_len=sum([len(i) for i in total_data ])

return ''.join(total_data)

##############

def start_server(recv_type=''):

sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

sock.bind(('',Port))

sock.listen(5)

print 'started on',Port

while True:

newsock,address=sock.accept()

print 'connected'

if recv_type=='size': result=recv_size(newsock)

elif recv_type=='end': result=recv_end(newsock)

elif recv_type=='timeout': result=recv_timeout(newsock)

else: result=newsock.recv(8192)

print 'got',result

if __name__=='__main__':

#start_server()

#start_server(recv_type='size')

#start_server(recv_type='timeout')

start_server(recv_type='end')

def send_size(data):

sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

sock.connect(('localhost',Port))

sock.sendall(struct.pack('>i', len(data))+data)

sock.close()

def send_end(data):

sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

sock.connect(('localhost',Port))

sock.sendall(data+End)

sock.close()

Discussion:

I employ a trivial server, to keep this as simple as possible. Just uncomment the type of receiving server you want to use to see the recv type chosen in action.

The recv_timeout function, which uses non-blocking sockets, will continue trying to get data as long as the client manages to even send a single byte. This is useful for moving data which you know very little about (like encrypted data), so cannot check for completion in a sane way.

The recv_end function tacks on an end marker understood by both the client and the server. One problem with this is that data cannot look like the marker.

The recv_size function looks for the size of the payload to be prepended to the data. I use a fixed length, 4 bytes. So then I know to always look for that. It is packed to allow a terse representation that can fit sys.maxint. This avoids the problem of data looking like the marker, however, even if it means a lot of data, you are limited w/the payload being the maximum number that can be packed. An interesting advantage of this method is that it can allocate data in larger chunks since it knows this size of the data ahead of time. For large streams of data, I saw it increase performace by 10 times.

To test this, in a another process, try using the functions that match with the server type.

send_size(data) #for recv_size

send_end(data) #for recv_end

sock.sendall(data) #for timeout or simple recv(8192)

#do not forget to close if you do a raw sendall

sock.close()

python socket接收图像 数据_python中socket接受数据的三种方法 | 学步园相关推荐

  1. python可以实现哪些功能_Python中实现机器学习功能的四种方法介绍

    本篇文章给大家带来的内容是关于Python中实现机器学习功能的四种方法介绍,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 在本文中,我们将介绍从数据集中选择要素的不同方法; 并使用S ...

  2. JavaScript 循环中调用异步函数的三种方法,及为什么 forEach 无法工作的分析

    JavaScript 循环中调用异步函数的三种方法,及为什么 forEach 无法工作的分析 业务分析 初版的问题 解决方案 传统的 for 循环 不使用 for 循环的解决方案 分析 forEach ...

  3. mysql在计算机管理中的路径怎么修改_Rstudio中修改工作路径的三种方法

    原文链接: Rstudio中修改工作路径的三种方法_weixin_44370085的博客-CSDN博客_rstudio改变工作目录​blog.csdn.net Rstudio中修改工作路径的三种方法 ...

  4. java 获取键盘点击_Java中获取键盘输入值的三种方法介绍

    程序开发过程中,需要从键盘获取输入值是常有的事,但Java它偏偏就没有像c语言给我们提供的scanf(),C++给我们提供的cin()获取键盘输入值的现成函数!Java没有提供这样的函数也不代表遇到这 ...

  5. Linux中创建Daemon进程的三种方法

    Linux中创建Daemon进程的三种方法 什么是daemon进程? Unix/Linux中的daemon进程类似于Windows中的后台服务进程,一直在后台运行运行,例如http服务进程nginx, ...

  6. 【转载】取得系统中网卡MAC地址的三种方法

    From:http://blog.csdn.net/zhangting1987/article/details/2732135 网卡地址这个概念有点混淆不清.因为实际上有两个地址,mac地址和物理地址 ...

  7. java中从键盘输入的三种方法以及Console输入

    java中从键盘输入的三种方法: import java.io.BufferedReader; import java.io.IOException; import java.io.InputStre ...

  8. 计算机启动应用程序的方法,excel的程序_Excel2010中启动应用程序的三种方法

    使用Excel时,需要先启动应用程序,怎么去进行操作启动它?今天,学习啦小编就教大家在Excel2010中启动应用程序的三种方法. Excel2010中启动应用程序的三种步骤如下: 1.开始菜单 在桌 ...

  9. linux系统中清空文件内容的三种方法

    1.使用vi/vim命令打开文件后,输入"%d"清空,后保存即可.但当文件内容较大时,处理较慢,命令如下: vim file_name :%d :wq 2.使用cat命令情况,命令 ...

最新文章

  1. python开发效率最高_公认8个效率最高的爬虫框架
  2. 键盘鼠标录制哪个好用_好看好用还不贵的那种键盘鼠标真的有吗?这次还真让我碰到了...
  3. .net 调用java service 代理类方法
  4. tensorflow入门之损失函数
  5. gc()两分钟了解JDK8默认垃圾收集器(附英文)
  6. win2008的搜索功能就是个鸡肋
  7. linux常用关机命令及其区别-Shutdown halt reboot init
  8. Codeforces Round #686 (Div. 3) E. Number of Simple Paths 基环树 + 容斥
  9. 现代软件工程 第二章 【个人技术】 练习与讨论
  10. MySQL.我的选择
  11. ubuntu 安装 guetzli
  12. 五大领域总目标指南_每日干货 | 五大领域 学前社会教育1
  13. 如何使用Aiseesoft iPhone Ringtone Maker for Mac在Mac上制作铃声
  14. 计算机二级操作题微盘,全国计算机等级考试题及答案二.pdf
  15. jQueryWEUI自定义对话框-带有textarea
  16. php deprecated,PHP Deprecated: Function eregi() is deprecated解决方法
  17. java脚本引擎Rhino 入门
  18. craftsmanship中文_中英文常用广告套语
  19. rhel7 http实例
  20. java克隆实现_JAVA里的深克隆与浅克隆实现

热门文章

  1. vue和微信小程序的区别、比较
  2. 为什么defineProperty不能检测到数组长度的“变化”
  3. 使用Java制作验证码
  4. java+selenium报异常org.openqa.selenium.StaleElementReferenceException的解决方案
  5. WebRequestDataBinder实现将请求参数映射为POJO对象
  6. CYQ.Data 数据框架 加快开源速度 发布V1.5.5版本源码
  7. Jayrock: JSON and JSON-RPC for .NET
  8. 前端 学习笔记day47 其他标签
  9. 后端根据查询条件生成excel文件返回给前端,vue进行下载
  10. SPOJ QTREE