粘包产生的原因分析:

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

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

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

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

发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(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. ES6 一些新特性的总结

    一.箭头函数 ES6中新增了一个箭头函数   ()=>,箭头函数通俗点讲就是匿名函数.箭头函数还有不同点在于改变函数中this,和js中的.bind  的方法差不多,继承后指向的不是最新的函数, ...

  2. css3中我们不知道的一些属性

    1.图片作为边框:border-image; 2.圆角问题:border-radius:上.下.左.右: 3.字体的阴影与自动换行: 阴影: h1 {text-shadow: 5px 5px 5px ...

  3. WinDbg设置托管进程断点

    WinDbg的Live模式调试..Net 托管代码 ,使用bp,bu,bm无法设置断点,也许是我不会.研究了下,托管代码有自己的命令,!BPMD 模块名 完全限定的方法名 步骤: 1.查找进程PID, ...

  4. 类、对象(java基础知识六)

    1.Java约定俗成 java约定俗成 1,类名接口名 一个单词首字母大写,多个单词每个单词首字母都大写 2,方法名和变量名 一个单词全部小写,多个单词从第二个单词首字母大写 建议:如果能用英语尽量用 ...

  5. Caused by: java.lang.IllegalArgumentException: Malformed \uxxxx encoding.

    application.properties中不能含有\符号.  只要遇到就会报这个错误. 解决方式:将application.properties中的 \ 改为 \\ 或者 /  

  6. Silverlight DataBinding Converter:根据binding对象调整显示

    Silverlight DataBinding Converter:根据binding对象调整显示 我希望写一系列关于Silverlight DataBinding的文章,分别讲解Silverligh ...

  7. 666 专题三 KMP &#38; 扩展KMP &#38; Manacher

    KMP: Problem A.Number Sequence d.求子串首次出现在主串中的位置 s. c. #include<iostream> #include<stdio.h&g ...

  8. SPOJ:Harbinger vs Sciencepal(分配问题&不错的DP&bitset优化)

    Rainbow 6 is a very popular game in colleges. There are 2 teams, each having some members and the 2 ...

  9. iOS NSInteger/NSUInteger与int/unsigned int、long/unsigned long之间的区别!

    在iOS开发中经常使用NSInteger和NSUInteger,而在其他的类似于C++的语言中,我们经常使用的是int.unsigned int.我们知道iOS也可以使用g++编译器,那么它们之间是否 ...

  10. python __builtins__ zip类 (71)

    71.'zip' , 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表.如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作 ...