原位置: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,time

Port=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()

pythonsocket数据对接_python中socket接受数据的三种方法相关推荐

  1. python socket接收图像 数据_python中socket接受数据的三种方法 | 学步园

    原位置:http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/408859 Description: An issue with socket ...

  2. 重点归纳:SPOT数据下载、影像波段数据介绍、多光谱数据模拟真彩色的三种方法【转载整合】

    SPOT数据下载.影像波段数据介绍.多光谱数据模拟真彩色的三种方法 前言 课程大作业 红外波段 SPOT卫星参数 SPOT-1,2,3 SPOT-4 SPOT-5 SPOT-6,7 模拟真彩色的三种方 ...

  3. Struts2中action接收参数的三种方法及ModelDriven跟Preparable接口结合JAVA反射机制的灵活用法...

    Struts2中action接收参数的三种方法及ModelDriven跟Preparable接口结合JAVA反射机制的灵活用法 www.MyException.Cn   发布于:2012-09-15 ...

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

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

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

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

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

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

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

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

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

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

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

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

最新文章

  1. 思考:行业客户项目中的代理商(国外厂商)
  2. Pycharm如何关掉jupyter notebook server
  3. About JXTA message reliable design
  4. 深入理解ReentrantLock
  5. IM云将给在线教育带来哪些变革?
  6. HBase原理-要弄懂的sequenceId
  7. received packet with own address as source address
  8. ROS 与 Matlab/Simulink联合仿真测试(1)
  9. 【复赛前排分享(二)】收好这份王牌优化指南,助你轻松上分无压力
  10. UNIX高级环境编程 第11、12章 线程同步及属性
  11. php宠物管理系统的开题报告,基于JSP的宠物医院开发与设计(开题报告)
  12. 安卓版LightBlue 低功耗蓝牙BLE设备调试
  13. 三坐标最小二乘法原理_【最小二乘法 | 高斯法】来认识一下传说中的最小二乘法...
  14. radon变换(c++、OpenCV实现)
  15. FlashPaper组件——api
  16. linux系统下 usb网卡的驱动安装
  17. 改良的用于情感分类的餐馆评论数据集
  18. 雅睿生物在创业板IPO终止:安信证券为保荐人,曾计划募资7.5亿元
  19. 学习笔记:Java虚拟机——JVM内存结构、垃圾回收、类加载与字节码技术
  20. C-Lodop提示“网页还没下载完毕,请稍等一下再操作.”

热门文章

  1. python语言有哪些关系运算符_python常用运算符有哪些?
  2. 服务器cpu最新一代,AMD新一代服务器级CPU曝光:Zen 4架构96核心,规格十分暴力...
  3. 边坡沉降预测【基于布谷鸟蚁群组合算法优化SVM】Matlab
  4. 改进YOLOv5、YOLOv7系列:7.改进DIoU-NMS,SIoU-NMS,EIoU-NMS,CIoU-NMS,GIoU-NMS改进
  5. python读取excel超链接
  6. 中式红木装修——体现中式浑厚底蕴的装修风格
  7. 软件动态分析喝静态分析_进行静态分析时,动态分析有什么用?
  8. 信用评分模型11111111
  9. 点对点协议PPP的特点
  10. 中国移动Cat.1通信模组-助力快速接入全球高质量LTE网络