VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > temp > 简明python教程 >
  • python基础(30):黏包、socket的其他方法(3)

'))

1.2.4 黏包成因总结

黏包现象只发生在tcp协议中:

1.从表面上看,黏包问题主要是因为发送方和接收方的缓存机制、tcp协议面向流通信的特点。

2.实际上,主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的

1.3 黏包的解决方案

1.3.1 解决方案一

问题的根源在于,接收端不知道发送端将要传送的字节流的长度,所以解决粘包的方法就是围绕,如何让发送端在发送数据前,把自己将要发送的字节流总大小让接收端知晓,然后接收端来一个死循环接收完所有数据。

 

 server:


	
  1. #_*_coding:utf-8_*_
  2. import socket,subprocess
  3. ip_port=('127.0.0.1',8080)
  4. s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  5. s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  6.  
  7. s.bind(ip_port)
  8. s.listen(5)
  9.  
  10. while True:
  11. conn,addr=s.accept()
  12. print('客户端',addr)
  13. while True:
  14. msg=conn.recv(1024)
  15. if not msg:break
  16. res=subprocess.Popen(msg.decode('utf-8'),shell=True,\
  17. stdin=subprocess.PIPE,\
  18. stderr=subprocess.PIPE,\
  19. stdout=subprocess.PIPE)
  20. err=res.stderr.read()
  21. if err:
  22. ret=err
  23. else:
  24. ret=res.stdout.read()
  25. data_length=len(ret)
  26. conn.send(str(data_length).encode('utf-8'))
  27. data=conn.recv(1024).decode('utf-8')
  28. if data == 'recv_ready':
  29. conn.sendall(ret)
  30. conn.close()

client:


	
  1. #_*_coding:utf-8_*_
  2. import socket,time
  3. s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
  4. res=s.connect_ex(('127.0.0.1',8080))
  5.  
  6. while True:
  7. msg=input('>>: ').strip()
  8. if len(msg) == 0:continue
  9. if msg == 'quit':break
  10.  
  11. s.send(msg.encode('utf-8'))
  12. length=int(s.recv(1024).decode('utf-8'))
  13. s.send('recv_ready'.encode('utf-8'))
  14. send_size=0
  15. recv_size=0
  16. data=b''
  17. while recv_size < length:
  18. data+=s.recv(1024)
  19. recv_size+=len(data)
  20.  
  21. print(data.decode('utf-8'))

存在的问题:

程序的运行速度远快于网络传输速度,所以在发送一段字节前,先用send去发送该字节流长度,这种方式会放大网络延迟带来的性能损耗。

1.3.2 方案二

刚刚的方法,问题在于我们在发送。

我们可以借助一个模块,这个模块可以把要发送的数据长度转换成固定长度的字节。这样客户端每次接收消息之前只要先接受这个固定长度字节的内容看一看接下来要接收的信息大小,那么最终接受的数据只要达到这个值就停止,就能刚好不多不少的接收完整的数据了。

(1)  struct模块

该模块可以把一个类型,如数字,转成固定长度的bytes。


	
  1. >>> struct.pack('i',1111111111111)
  2.  
  3. struct.error: 'i' format requires -2147483648 <= number <= 2147483647 #这个是范围


	
  1. import json,struct
  2. #假设通过客户端上传1T:1073741824000的文件a.txt
  3.  
  4. #为避免粘包,必须自定制报头
  5. header={'file_size':1073741824000,'file_name':'/a/b/c/d/e/a.txt','md5':'8f6fbf8347faa4924a76856701edb0f3'}

相关教程