粘包产生的原因分析:

第一点:客户端向服务端发起命令请求,服务端接受命令请求,并返回对应的信息,如果信息过大,客户端一次接受不了,那么下一次请求依然返回

上一个命令的内容,就出现了粘包的情况。

第二点:发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据了很小,会合到一起,产生粘包)

所谓粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的。

发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。这样做,虽然节省了时间,但是发出的包却粘在了一起,造成粘包现象。

简单点的报头(有注释)

from socket import *  # socket里面很多功能用得到,属于特殊情况
import subprocess
import struct server=socket(AF_INET,SOCK_STREAM) # 生成套接字,绑定ip_port,服务端处于倾听状态
server.bind(('127.0.0.1',8080))
server.listen(5) while True:
conn,client_addr=server.accept() # 套接字和绑定的ip_port
print('新的客户端',client_addr) while True: # 下面的不循环结束不会进入下一个客户端
try:
cmd=conn.recv(1024) # cmd=b'dir' # 命令一般不会超过1024 不用管
if len(cmd) == 0:break # 运行系统命令 为什么不用system 因为system???
obj=subprocess.Popen(cmd.decode('utf-8'), # 字节解压成字符串
shell=True,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE
) stdout=obj.stdout.read()# 读出管道里数据 顺序不要乱 先stdout 然后stderr
stderr=obj.stderr.read() #1、先制作报头(固定长度)
total_size=len(stdout) + len(stderr) # 数据的总长度(整型)
header=struct.pack('i',total_size) # 把数据的长度按照i格式包装为固定的四个字节的报头 #2、先发送固定长度的报头
conn.send(header) # 为什么能解决粘包问题?因为把报头固定为四个字节,接受的时候固定接受 #3、再发送真实的数据
conn.send(stdout)
conn.send(stderr)
except ConnectionResetError:
break conn.close()

服务端

from socket import *
import struct client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080)) while True:
cmd=input('>>: ').strip()
if len(cmd) == 0:continue
client.send(cmd.encode('utf-8')) #1、先收固定长度的报头
header=client.recv(4) # 先接收固定长度的报头 #2、从报头中解析出对数据的描述信息
total_size=struct.unpack('i',header)[0] # 按照i格式解析出报头的数据信息,解析出来是一个元组(a,)形式,取第一个 #3、再收真实的数据
recv_size=0 # 应用层接受数据,初始数据为0
res=b''
while recv_size < total_size : # 接受数据小于传送过来的数据时,循环会一直进行下去
data=client.recv(1024)
res+=data
recv_size+=len(data) print(res.decode('gbk'))

客户端

复杂一点的报头(有注释)

from socket import *
import subprocess
import struct
import json server=socket(AF_INET,SOCK_STREAM)
server.bind(('127.0.0.1',8080))
server.listen(5) while True:
conn,client_addr=server.accept()
print('新的客户端',client_addr) while True:
try:
cmd=conn.recv(1024) #cmd=b'dir'
if len(cmd) == 0:break # 运行系统命令
obj=subprocess.Popen(cmd.decode('utf-8'),
shell=True,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE
) stdout=obj.stdout.read()
stderr=obj.stderr.read() #先制作报头
header_dic={ # 报头信息 包含文件名 文件大小 hash值
'filename':'a.txt',
'total_size':len(stdout) + len(stderr),
'hash':'xasf123213123'
}
header_json=json.dumps(header_dic) # 将包含报头信息的字典存成字符串格式
header_bytes=header_json.encode('utf-8') # 字符串编码成字节形式
print(header_json,type(header_json)) #1、先把报头的长度len(header_bytes)打包成4个bytes,然后发送
conn.send(struct.pack('i',len(header_bytes)))
#2、发送报头
conn.send(header_bytes)
#3、再发送真实的数据
conn.send(stdout)
conn.send(stderr)
except ConnectionResetError:
break conn.close()

服务端

from socket import *
import struct
import json client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080)) while True:
cmd=input('>>: ').strip()
if len(cmd) == 0:continue
client.send(cmd.encode('utf-8')) #1、先收4个字节,该4个字节中包含报头的长度
header_len=struct.unpack('i',client.recv(4))[0]
print(client.recv(4))
print(header_len) #2、再接收报头
header_bytes=client.recv(header_len) #从报头中解析出想要的内容
header_json=header_bytes.decode('utf-8')
header_dic=json.loads(header_json)
print(header_dic)
total_size=header_dic['total_size'] #3、再收真实的数据
recv_size=0
res=b''
while recv_size < total_size :
data=client.recv(1024)
res+=data
recv_size+=len(data) print(res.decode('gbk'))

客户端

模拟ssh的远程网络传输的更多相关文章

  1. ssh 中 远程文件传输

    scp 命令是 SSH 中最方便有用的命令了,试想,在两台服务器之间直接传送文件,仅仅用 scp 一个命令就完全解决了. 你可以在一台服务器上 以 root 身份运行 #scp servername: ...

  2. golang通过ssh实现远程文件传输

    使用ssh远程操作文件, 主要是创建ssh, 直接上代码 import ( "fmt" "github.com/pkg/sftp" "golang.o ...

  3. 网络编程 - 1.简单的套接字通信/2.加上通信循环/3.bug修复/4.加上链接循环/5.模拟ssh远程执行命令

    1.简单的套接字通信 服务端 ''' 服务端 接电话 客户端 打电话 1.先启动服务端 2.服务端有两种套接字 1.phone 用来干接收链接的 2.conn 用来干收发消息的 ''' import ...

  4. 网络编程之模拟ssh远程执行命令、粘包问题 、解决粘包问题

    目录 模拟ssh远程执行命令 服务端 客户端 粘包问题 什么是粘包 TCP发送数据的四种情况 粘包的两种情况 解决粘包问题 struct模块 解决粘包问题 服务端 客户端 模拟ssh远程执行命令 服务 ...

  5. [Python 网络编程] TCP、简单socket模拟ssh (一)

    OSI七层模型(Open System Interconnection,开放式系统互联) 应用层 网络进程访问应用层: 为应用程序进程(例如:电子邮件.文件传输和终端仿真)提供网络服务: 提供用户身份 ...

  6. 模拟ssh远程执行命令,粘包问题,基于socketserver实现并发的socket

    06.27自我总结 1.模拟ssh远程执行命令 利用套接字编来进行远程执行命令 服务端 from socket import * import subprocess server = socket(A ...

  7. Python 简单socket模拟ssh

    OSI七层模型(Open System Interconnection,开放式系统互联) 应用层 表示层 回话层 传输层 tcp,udp 网络层 ip,icmp 数据链路层 mac地址 物理层 物理网 ...

  8. Linux基础命令介绍七:网络传输与安全 wget curl rsync iptables

    本篇接着介绍网络相关命令:wget 文件下载工具.curl 网络数据传输工具.rsync 文件传输工具等. 本篇接着介绍网络相关命令 1.wget 文件下载工具 wget [option]... [U ...

  9. mac ssh,mac xshell,xshell替代,ssh客户端,ssh工具,远程桌面加速

    下载地址 Windows版下载地址:http://www.hostbuf.com/downloads/finalshell_install.exe Mac版,Linux版安装及教程:http://ww ...

随机推荐

  1. Awesome Adb——一份超全超详细的 ADB 用法大全【转】

    本文转载自:https://juejin.im/entry/57c00fe4c4c971006179838a ADB,即 Android Debug Bridge,它是 Android 开发/测试人员 ...

  2. RedisCluster集群搭建

    搭建集群方案 安装部署任何一个应用其实都很简单,只要安装步骤一步一步来就行了.下面说一下 Redis 集群搭建规划,由于集群至少需要6个节点(3主3从模式),所以,没有这么多机器给我玩,我本地也起不了 ...

  3. Swift语言学习(三)基础操作符

    操作符是用于检测.更改或者组合值的特殊符号或短语.例如,加法操作符 (+) 将两个数字加到一起 (如 let i = 1 + 2).更复杂的例子包括逻辑与操作符 && (如 if en ...

  4. Python的单元测试工具——doctest

    doctest是一个python标准库自带的轻量单元测试工具,适合实现一些简单的单元测试.它可以在docstring中寻找测试用例并执行,比较输出结果与期望值是否符合. 基本用法使用doctest需要 ...

  5. 使用mysqlfrm恢复frm表结构,获得建表语句

    1.mysqlfrm 是一个恢复性质的工具,用来读取.frm文件并从该文件中找到表定义数据生成CREATE语句. 下载链接:https://downloads.mysql.com/archives/u ...

  6. 任务25:IHostEnvironment和 IApplicationLifetime介绍

    任务25:IHostEnvironment和 IApplicationLifetime介绍 IHostingEnvironment这个里面有一些参数,比如我们当前应用程序的名称.目录的. await ...

  7. 一个获取google chrome扩展crx文件信息的PHP操作类

    此类中实现了从crx文件获取扩展的Appid.获取manifest.json文件内容.将crx文件转换为一般zip文件 代码如下: <?php class CrxParserException ...

  8. STS和Eclipse安装Lombok插件

    参考:https://www.cnblogs.com/caozx/p/9510354.html 参考:https://blog.csdn.net/wutian90/article/details/87 ...

  9. Gradle系列之一 Groovy语法精讲

    Gradle技术之一 Groovy语法精讲 gradle脚本是基于groovy语言开发的,想要学好gradle必须先要对groovy有一个基本的认识 1. Groovy特点 groovy是一种DSL语 ...

  10. HDU6069:Counting Divisors(因子数统计|区间筛)

    题意 计算\(\sum_{i=l}^kd(i^k)(d_i代表i的因子数)\) 分析 比赛搞了3个小时都没搞出来,有两个思维上的trick 1.要先遍历素数,再遍历[L,R],而不是枚举每个数,然后对 ...