四. 网络编程(TCP 黏包)
时间:2019-07-04
本文章向大家介绍四. 网络编程(TCP 黏包),主要包括四. 网络编程(TCP 黏包)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
一 .黏包现象(TCP)
1.黏包成因
TCP协议中的数据传递
tcp协议的拆包机制
当发送端缓冲区的长度大于网卡的MTU时,tcp会将这次发送的数据拆成几个数据包发送出去。
MTU是Maximum Transmission Unit的缩写。意思是网络上传送的最大数据包。MTU的单位是字节。 大部分网络设备的MTU都是1500。
如果本机的MTU比网关的MTU大,大的数据包就会被拆开来传送,这样会产生很多数据包碎片,增加丢包率,降低网络速度
面向流的通信特点和Nagle算法
TCP(transport control protocol,传输控制协议)是面向连接的,面向流的,提供高可靠性服务。
收发两端(客户端和服务器端)都要有一一成对的socket,因此,发送端为了将多个发往接收端的包,更有效的发到对方
,使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。
这样,接收端,就难于分辨出来了,必须提供科学的拆包机制。 即面向流的通信是无消息保护边界的。
对于空消息:tcp是基于数据流的,于是收发的消息不能为空,这就需要在客户端和服务端都添加空消息的处理机制,防止程序卡住
,而udp是基于数据报的,即便是你输入的是空内容(直接回车),也可以被发送,udp协议会帮你封装上消息头发送过去。
可靠黏包的tcp协议:tcp的协议数据不会丢,没有收完包,下次接收,会继续上次继续接收,己端总是在收到ack时才会清除缓冲区内容。数据是可靠的,但是会粘包。
udp是基于数据报的,即便是你输入的是空内容(直接回车),也可以被发送,udp协议会帮你封装上消息头发送过去。 不可靠不黏包的udp协议:udp的recvfrom是阻塞的,一个recvfrom(x)必须对唯一一个sendinto(y),收完了x个字节的数据就算完成,若是y;x数据就丢失,这意味着udp根本不会粘包,
但是会丢数据,不可靠
subprocess模块是python从2.4版本开始引入的模块。
让我们基于tcp先制作一个远程执行命令的程序(命令ls -l ; lllllll ; pwd)
import subprocess # subprocess模块是python从2.4版本开始引入的模块。 # 主要用来取代 一些旧的模块方法,如os.system、os.spawn*、os.popen*、commands.*等。subprocess通过子进程来执行外部指令 cmd=subprocess.Popen("dir",shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) print(cmd.stderr.read().decode("gbk")) print(cmd.stdout.read().decode("gbk"))
2.基于tcp协议实现的黏包
server1
我们基于tcp先制作一个远程执行命令的程序(命令ls -l ; lllllll ; pwd)
import socket # import subprocess server=socket.socket() server.bind(("192.168.59.1",8600)) server.listen(5) conn,addr=server.accept() while True: cmd = input("请输入你终端命令:") conn.send(cmd.encode("utf-8")) ret = conn.recv(1024) print(ret.decode("utf-8"),"这是服务器哈哈哈") conn.close() server.close()
client1 我们基于tcp先制作一个远程执行命令的程序(命令ls -l ; lllllll ; pwd)
import socket import subprocess client=socket.socket() client.connect(("192.168.59.1",8600)) while True: msg=client.recv(1024) ret = subprocess.Popen(msg.decode('gbk'), shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) err='我是err'+(ret.stderr.read()).decode("gbk") out='我是out'+(ret.stderr.read()).decode("gbk") print(err) print(out) client.send(err.encode("utf-8")) client.send(out.encode("utf-8")) print(msg.decode("utf-8")) client.close()
server2 from socket import * import subprocess ip_port=('127.0.0.1',8888) server=socket(AF_INET,SOCK_STREAM) server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) server.bind(ip_port) server.listen(5) while True: conn,addr=server.accept() print('客户端',addr) while True: cmd=conn.recv(1024) if len(cmd) == 0:break res=subprocess.Popen(cmd.decode('utf-8'),shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE) stderr=res.stderr.read() stdout=res.stdout.read() conn.send(stderr) conn.send(stdout)
client1 import socket ip_port=('127.0.0.1',8888) s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) res=s.connect_ex(ip_port) while True: msg=input('请输入命令哈: ').strip() if len(msg) == 0:continue if msg == 'quit':break s.send(msg.encode('utf-8')) act_res=s.recv(1024) print(act_res.decode('utf-8'),end='')
情况二 接收方的缓存机制
接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包)
总结
黏包现象只发生在tcp协议中:
1.从表面上看,黏包问题主要是因为发送方和接收方的缓存机制、tcp协议面向流通信的特点。
2.实际上,主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的
原文地址:https://www.cnblogs.com/Sup-to/p/11135465.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- PHP常用的类封装小结【4个工具类】
- 微信公众号之主动给用户发送消息功能
- laravel异步监控定时调度器实例详解
- python按顺序重命名文件并分类转移到各个文件夹中的实现代码
- Python实现删除某列中含有空值的行的示例代码
- python打开音乐文件的实例方法
- PHP基础之输出缓冲区基本概念、原理分析
- 基于python实现删除指定文件类型
- sync-player:使用websocket实现异地同步播放视频
- CentOS7.0下安装PHP5.6.30服务的教程详解
- PHP实现微信提现功能
- PHP实现SMTP邮件的发送实例
- php实现有序数组旋转后寻找最小值办法
- PHP APP微信提现接口代码
- ThinkPHP5 的简单搭建和使用详解