socket编程之黏包
2024-10-06 14:41:31
原理概述
上图是我在学习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()
最新文章
- 带交互的 iOS 产品原型可以用什么软件制作?
- vs打开项目出现“尚未配置为Web项目XXXX指定的本地IIS URL HTTP://localhost:…… .要打开此项目,需要配置虚拟目录……”提示
- 如何在win7上安装ant-design
- 0,SFDC 开发篇 - 开发框架和APEX语法
- 【MySQL】探究之TIMESTAMP
- Python中的库使用之一 PIL
- Overview Of Portal Registry And Content References
- Linux基础--例行工作
- 关于IE调试模式下才能显示效果
- S5PV210启动过程分析
- MySQL主从同步、读写分离配置步骤
- Linux Shell脚本入门--Uniq命令
- CentOS 6.2 安装vsftpd 服务器(转)
- jquery判断对象是否显示或隐藏
- 【TensorFlow篇】--Tensorflow框架初始,实现机器学习中多元线性回归
- elasticsearch系列一:elasticsearch(ES简介、安装&;配置、集成Ikanalyzer)
- Fiddler抓包【2】_捕获设置
- Java基础学习-Eclipse综述和运算符的使用
- 消息队列(Message Queue)简介及其使用
- Android为TV端助力 同时setTag两次,保存多种值
热门文章
- tomcat配置CA证书后,https的接口url请求很慢,大概率会超时
- [原创]VSCode debug jest的配置
- django中权限控制到按钮级别
- harbor批量导出镜像
- AttributeError: 'int' object has no attribute 'upper'
- Girls and Boys POJ - 1466 【(二分图最大独立集)】
- JAVA的带参数的方法
- 五十一.Openstack概述 部署安装环境 、 部署Openstack OpenStack操作基础
- set/unset
- Collection接口详解