原理概述

  上图是我在学习python的socket编程中遇到的黏包问题所画,以实例来说明这个高大上的黏包问题。

  我们知道socket()实例中sendall()方法是无论数据有多大,一次性提交写入缓冲区(应用层);再来看接收端,recv()方法有个参数为buffsize,没错buffsize就是套接口的发送缓冲区的大小了。所以数据大于SO_SNDBUF的就会被分块传输,问题就来了,当两次提交的数据都比较大,刚好第一次尾与第二次的首同一时间待在了SO_SNDBUF里,被接收到了,这就是黏包。

  一句话:黏包最本质的原因就是接收方不知道接收的包有多大!

解决方法(应用层维护消息和消息边界):

  1. 定长包
  2. 包尾加上\r\n标记(FTP)
  3. 包头增加包体长度。
  4. 复杂的应用层协议。

实例

  本实例多线程实例,实现的是客户端向服务端输入系统命令,服务器返回命令在本机上的执行结果。因为有些命令返回的结果是远大于1024的,所以可能出现黏包的问题。本实例的解决方案是第三条,server端每次向client端返回命令执行结果前,先发送包体大小并得到client端返回的确认信息,再发送数据,程序结构上避免了黏包问题。

TCPSocket服务端

#!/usr/bin/env python
#-*- coding:utf-8 -*-
import SocketServer
import os class Myserver(SocketServer.BaseRequestHandler): def handle(self):
conn = self.request
print "Client from:",self.client_address
conn.sendall("请输入您要查询的命令")
flag = True
while flag:
data = conn.recv(1024)
print "receive cmd: %s"%data
if data == "exit":
flag = False
else:
ret = os.popen(data).read().decode("gbk").encode("utf-8")
         #发送包大小
conn.sendall(str(len(ret)))
#收到客户端确认消息。
scOK = conn.recv(1024)
         #发送包体内容
conn.sendall(ret) if __name__ == "__main__":
server = SocketServer.ThreadingTCPServer(("localhost",8000),Myserver)
server.serve_forever()

TCPSocket客户端

#!/usr/bin/env python
#-*- coding:utf-8 -*-
import socket
sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sk.connect(("127.0.0.1",8000))
sk.settimeout(5)
data = sk.recv(1024)
print "SocketServer: %s" % data
while True:
reSize = 0
msg = raw_input("Input:")
sk.sendall(msg)
  #接收包的大小
totleSize = int(sk.recv(1024))
  #收到包的大小后,给server端发送确认信息。
sk.sendall("It is ok")
while True:
data = sk.recv(1024)
reSize += len(data)
    #当接收数据等于包的size后,跳出循环,停止 接收。
if reSize == totleSize:
print data
break
print data
if msg == "exit":
break
sk.close()

 

最新文章

  1. 带交互的 iOS 产品原型可以用什么软件制作?
  2. vs打开项目出现“尚未配置为Web项目XXXX指定的本地IIS URL HTTP://localhost:…… .要打开此项目,需要配置虚拟目录……”提示
  3. 如何在win7上安装ant-design
  4. 0,SFDC 开发篇 - 开发框架和APEX语法
  5. 【MySQL】探究之TIMESTAMP
  6. Python中的库使用之一 PIL
  7. Overview Of Portal Registry And Content References
  8. Linux基础--例行工作
  9. 关于IE调试模式下才能显示效果
  10. S5PV210启动过程分析
  11. MySQL主从同步、读写分离配置步骤
  12. Linux Shell脚本入门--Uniq命令
  13. CentOS 6.2 安装vsftpd 服务器(转)
  14. jquery判断对象是否显示或隐藏
  15. 【TensorFlow篇】--Tensorflow框架初始,实现机器学习中多元线性回归
  16. elasticsearch系列一:elasticsearch(ES简介、安装&配置、集成Ikanalyzer)
  17. Fiddler抓包【2】_捕获设置
  18. Java基础学习-Eclipse综述和运算符的使用
  19. 消息队列(Message Queue)简介及其使用
  20. Android为TV端助力 同时setTag两次,保存多种值

热门文章

  1. tomcat配置CA证书后,https的接口url请求很慢,大概率会超时
  2. [原创]VSCode debug jest的配置
  3. django中权限控制到按钮级别
  4. harbor批量导出镜像
  5. AttributeError: 'int' object has no attribute 'upper'
  6. Girls and Boys POJ - 1466 【(二分图最大独立集)】
  7. JAVA的带参数的方法
  8. 五十一.Openstack概述 部署安装环境 、 部署Openstack OpenStack操作基础
  9. set/unset
  10. Collection接口详解