socket编程之黏包
原理概述
上图是我在学习python的socket编程中遇到的黏包问题所画,以实例来说明这个高大上的黏包问题。
我们知道socket()实例中sendall()方法是无论数据有多大,一次性提交写入缓冲区(应用层);再来看接收端,recv()方法有个参数为buffsize,没错buffsize就是套接口的发送缓冲区的大小了。所以数据大于SO_SNDBUF的就会被分块传输,问题就来了,当两次提交的数据都比较大,刚好第一次尾与第二次的首同一时间待在了SO_SNDBUF里,被接收到了,这就是黏包。
一句话:黏包最本质的原因就是接收方不知道接收的包有多大!
解决方法(应用层维护消息和消息边界):
- 定长包
- 包尾加上\r\n标记(FTP)
- 包头增加包体长度。
- 复杂的应用层协议。
实例
本实例多线程实例,实现的是客户端向服务端输入系统命令,服务器返回命令在本机上的执行结果。因为有些命令返回的结果是远大于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()
socket编程之黏包的更多相关文章
- python socket编程和黏包问题
一.基于TCP的socket tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接服务端,有顺序,不重复,可靠.不会被加上数据边界. server端 import socket sk = so ...
- Python网络编程基础 ❷ 基于upd的socket服务 TCP黏包现象
TCP的长连接 基于upd的socket服务 TCP黏包现象
- python/socket编程之粘包
python/socket编程之粘包 粘包 只有TCP有粘包现象,UDP永远不会粘包. 首先需要掌握一个socket收发消息的原理 发送端可以是1k,1k的发送数据而接受端的应用程序可以2k,2k的提 ...
- 2、网络并发编程--套接字编程、黏包问题、struct模块、制作简易报头、上传文件数据
昨日内容回顾 面向对象复习(json序列化类) 对象.类.父类的概念 三大特性:封装 继承 多态 双下开头的方法(达到某个条件自动触发) __init__:对象实例化自动触发 __str__:对象执行 ...
- Python网络编程之黏包问题
二.解决黏包问题 2.1 解决黏包方法1 计算消息实体的大小 服务端接受两次,一次时消息大小,二次是消息实体,解决消息实体黏包 客户端发送两次,一次是消息大小,一次是消息实体 在两次收发之间加入一次多 ...
- Python学习笔记【第十四篇】:Python网络编程二黏包问题、socketserver、验证合法性
TCP/IP网络通讯粘包问题 案例:模拟执行shell命令,服务器返回相应的类容.发送指令的客户端容错率暂无考虑,按照正确的指令发送即可. 服务端代码 # -*- coding: utf- -*- # ...
- 《Python》网络编程之黏包
黏包 一.黏包现象 同时执行多条命令之后,得到的结果很可能只有一部分,在执行其他命令的时候又接收到之前执行的另外一部分结果,这种显现就是黏包. server端 import socket sk = s ...
- socket模块和黏包问题
socket套接字简介 编写cs架构的程序 实现数据交互 OSI七层相当复杂 socket套接字是一门技术 socket模块>>>:提供了快捷方式 不需要自己处理每一层 " ...
- 网络编程- 解决黏包现象方案二之struct模块(七)
上面利用struct模块与方案一比较,减少一次发送和接收请求,因为方案一无法知道client端发送内容的长度到底有多长需要和接收OK.多一次请求防止黏包,减少网络延迟
随机推荐
- H5:加载原理,慢加载和卡顿原因分析,
前端H5工作原理: 请求和显示原理 H5页面卡顿原因分析: 1.动画太多:渲染重绘占用GPU 2.页面操作导致重绘频繁 3.页面元素复杂:资源类标签太多(图像/视频/dom树太长) 4.内置webvi ...
- 使用JXL组件操作Excel和导出文件
这段时间参与的项目要求做几张Excel报表,由于项目框架使用了jxl组件,所以把jxl组件的详细用法归纳总结一下.本文主要讲述了以下内容: JXL及相关工具简介 如何安装JXL JXL的基本操作 创建 ...
- springBoot maven项目打成jar包
springBoot项目打包springBoot项目打包最常用且最简单的方式是用springBoot的打包plugin <plugin> <groupId>org.spring ...
- 如何使用python异常---runtimeError方法
RuntimeError def ilove(name): if name=='陈培昌': print('i love {0}'.format(name)) elif name == '程劲': pr ...
- go html 转字符串存mysql表中
func HTMLMarshal(str string) (returnStr string) { bf := bytes.NewBuffer([]byte{}) jsonEncoder := jso ...
- Material Icons 查找的替代办法
1 问题 1.1 国内访问 google 困难,众所周知 1.2 在平时的工作中使用 Material Icons 如何查询呢 2 办法 2.1 github.com 把包 download 2.2 ...
- 参数类型 (Mapper.java)常用
UserBaseInfo selectByMobile(@Param("mobile")String mobile,@Param("isDeleted")Int ...
- vue中setInterval的清除
两种清除setInterval的方式: 方案一: data() { return { timer: null // 定时器名称 } }, mouted() { this.timer = (() =&g ...
- 「CQOI2006」简单题 线段树
「CQOI2006」简单题 线段树 水.区间修改,单点查询.用线段树维护区间\([L,R]\)内的所有\(1\)的个数,懒标记表示为当前区间是否需要反转(相对于区间当前状态),下方标记时懒标记取反即可 ...
- 面向对象(OOP)笔记
1.本质:以类的方式组织代码,以对象的方式组织(封装)数据 2.对象:是具体的事物 3.类:是对对象的抽象(抽象 抽出象的部分) 先有具体的对象,然后抽象各个对象之间象的部分,归纳出类 通过类再认识其 ...