python基于socket模拟实现ssh远程执行命令


Posted in Python onDecember 05, 2020

一、subprocess.Popen()

subprocess模块定义了一个类: Popen

类原型:

class subprocess.Popen( args, 
  bufsize = 0, 
  executable = None, 
  stdin = None, 
  stdout = None, 
  stderr = None, 
  preexec_fn = None, 
  close_fds = False, 
  shell = False, 
  cwd = None, 
  env = None, 
  universal_newlines = False, 
  startupinfo = None, 
  creationflags = 0)

我们只需要关注其中几个参数:

  • args:

args参数。可以是一个字符串,可以是一个包含程序参数的列表。要执行的程序一般就是这个列表的第一项,或者是字符串本身。

  • shell=True:

在Linux下,当shell=True时,如果arg是个字符串,就使用shell来解释执行这个字符串。如果args是个列表,则第一项被视为命令,其余的都视为是给shell本身的参数。也就是说,等效于:
subprocess.Popen(['/bin/sh', '-c', args[0], args[1], ...])

  • stdin stdout和stderr:

stdin stdout和stderr,分别表示子程序的标准输入、标准输出和标准错误。可选的值有PIPE或者一个有效的文件描述符(其实是个正整数)或者一个文件对象,还有None。如果是PIPE,则表示需要创建一个新的管道,如果是None,不会做任何重定向工作,子进程的文件描述符会继承父进程的。另外,stderr的值还可以是STDOUT,表示子进程的标准错误也输出到标准输出。

二、粘包现象

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

须知:只有TCP有粘包现象,UDP永远不会粘包

粘包不一定会发生,如果发生了:1.可能是在客户端已经粘了;2.客户端没有粘,可能是在服务端粘了

缓冲区的作用:存储少量数据

如果你的网络出现短暂的异常或者波动,接收数据就会出现短暂的中断,影响你的下载或者上传的效率。但是,缓

冲区解决了上传下载的传输效率的问题,带来了黏包问题。

收发的本质:不一定是一收一发

三、为什么出现粘包?

1,接收方没有及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包)recv会产生黏包(如果recv接受的数据量(1024)小于发送的数据量,第一次只能接收规定的数据量1024,第二次接收剩余的数据量)

2,发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据也很小,会合到一起,产生粘包)send 也可能发生粘包现象。(连续send少量的数据发到输出缓冲区,由于缓冲区的机制,也可能在缓冲区中不断积压,多次写入的数据被一次性发送到网络)

出现粘包现象的代码实例

server. py

import socket
import subprocess

# 建立
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

# 绑定
phone.bind(('127.0.0.1', 8081))

# 监听
phone.listen(5)

# 通信循环
while True:
  # 接收客户端连接请求
  conn, client_addr = phone.accept()
  while True:
    # 接收客户端数据/命令
    cmd = conn.recv(1024)
    if not cmd:
      break
    # 创建管道
    obj = subprocess.Popen(cmd.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    stdout = obj.stdout.read()
    stderr = obj.stderr.read()
    # 向客户端发送数据
    conn.send(stdout)
    conn.send(stderr)
  # 结束连接
  conn.close()

# 关闭套接字
phone.close()

client. py

import socket

# 建立
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 连接
phone.connect(('127.0.0.1', 8081))
while True:
  cmd = input('>>> ').strip()
  if not cmd:
    continue
  if cmd == 'quit':
    break
  # 给服务端发送数据/命令
  phone.send(cmd.encode('utf-8'))
  # 接收服务端数据/命令
  data = phone.recv(1024)
  print(data.decode('utf-8'))

# 关闭套接字
phone.close()

粘包现象运行结果

python基于socket模拟实现ssh远程执行命令

python基于socket模拟实现ssh远程执行命令

python基于socket模拟实现ssh远程执行命令

可以观察到执行两次ls命令后,服务端返回的仍然是ifconfig命令的结果,最后一次ls命令的末尾才出现ls命令返回的部分结果

四、解决粘包问题的代码实例
server. py

import socket
import subprocess
import json
import struct

# 建立
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

# 绑定
phone.bind(('127.0.0.1', 8081))

# 监听
phone.listen(5)

# 通信循环
while True:
  # 接收客户端连接请求
  conn, client_addr = phone.accept()
  while True:
    # 接收客户端数据/命令
    cmd = conn.recv(1024)
    if not cmd:
      continue
    # 创建数据流管道
    obj = subprocess.Popen(cmd.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    stdout = obj.stdout.read()
    stderr = obj.stderr.read()
    # 向客户端发送数据

    # 解决粘包问题
    # 1.制作固定长度的报头
    header_dic = {
      'filename': 'a.txt',
      'total_size': len(stdout)+len(stderr)
    }
    # 序列化报头
    header_json = json.dumps(header_dic) # 序列化为byte字节流类型
    header_bytes = header_json.encode('utf-8') # 编码为utf-8(Mac系统)
    # 2.先发送报头的长度
    # 2.1 将byte类型的长度打包成4位int
    conn.send(struct.pack('i', len(header_bytes)))
    # 2.2 再发报头
    conn.send(header_bytes)
    # 2.3 再发真实数据
    conn.send(stdout)
    conn.send(stderr)
  # 结束连接
  conn.close()

# 关闭套接字
phone.close()

client. py

import socket
import struct
import json

# 建立
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 连接
phone.connect(('127.0.0.1', 8081))
while True:
  cmd = input('>>> ').strip()
  if not cmd:
    continue
  if cmd == 'quit':
    break
  # 给服务端发送命令
  phone.send(cmd.encode('utf-8'))
  # 接收服务端数据

  # 1.先收报头长度
  obj = phone.recv(4)
  header_size = struct.unpack('i', obj)[0]
  # 2.收报头
  header_bytes = phone.recv(header_size)
  # 3.从报头中解析出数据的真实信息(报头字典)
  header_json = header_bytes.decode('utf-8')
  header_dic = json.loads(header_json)
  total_size = header_dic['total_size']
  # 4.接受真实数据
  recv_size = 0
  recv_data = b''
  while recv_size < total_size:
    res = phone.recv(1024)
    recv_data += res
    recv_size += len(res)
  print(recv_data.decode('utf-8'))

# 关闭套接字
phone.close()

以上就是python基于socket模拟实现ssh远程执行命令的详细内容,更多关于python基于socket实现ssh远程执行命令的资料请关注三水点靠木其它相关文章!

以上就是python基于socket模拟实现ssh远程执行命令的详细内容,更多关于python socket的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
pyqt和pyside开发图形化界面
Jan 22 Python
Python实现数据库编程方法详解
Jun 09 Python
python发送HTTP请求的方法小结
Jul 08 Python
Python中的字典与成员运算符初步探究
Oct 13 Python
Python中max函数用于二维列表的实例
Apr 03 Python
Python合并2个字典成1个新字典的方法(9种)
Dec 19 Python
Python3基本输入与输出操作实例分析
Feb 14 Python
解决pycharm不能自动补全第三方库的函数和属性问题
Mar 12 Python
python递归调用中的坑:打印有值, 返回却None
Mar 16 Python
Python字典fromkeys()方法使用代码实例
Jul 20 Python
Python字典实现伪切片功能
Oct 28 Python
Python截图并保存的具体实例
Jan 14 Python
Python实现PS滤镜中的USM锐化效果
Dec 04 #Python
python 模拟登陆github的示例
Dec 04 #Python
python中round函数保留两位小数的方法
Dec 04 #Python
python中pow函数用法及功能说明
Dec 04 #Python
python对输出的奇数偶数排序实例代码
Dec 04 #Python
python中entry用法讲解
Dec 04 #Python
利用python制作拼图小游戏的全过程
Dec 04 #Python
You might like
多数据表共用一个页的新闻发布
2006/10/09 PHP
PHP GD库生成图像的几个函数总结
2014/11/19 PHP
php对象在内存中的存在形式分析
2015/02/03 PHP
PHP实现全角字符转为半角方法汇总
2015/07/09 PHP
PHP使用MPDF类生成PDF的方法
2015/12/08 PHP
js获取select默认选中的Option并不是当前选中值
2014/05/07 Javascript
js与css实现弹出层覆盖整个页面的方法
2014/12/13 Javascript
js实现交换运动效果的方法
2015/04/10 Javascript
JQuery包裹DOM节点的方法
2015/06/11 Javascript
jQuery实现的鼠标滑过弹出放大图片特效
2016/01/08 Javascript
JS和jQuery使用submit方法无法提交表单的原因分析及解决办法
2016/05/17 Javascript
Javascript基础_嵌入图像的简单实现
2016/06/14 Javascript
JavaScript动态添加事件之事件委托
2016/07/12 Javascript
微信小程序 loading 详解及实例代码
2016/11/09 Javascript
浅谈layer的iframe弹窗给里面的标签赋值的问题
2016/11/10 Javascript
ionic2 tabs使用 Modal底部tab弹出框
2016/12/30 Javascript
nginx配置React静态页面的方法教程
2017/11/03 Javascript
vue+vuex+axios+echarts画一个动态更新的中国地图的方法
2017/12/19 Javascript
nuxt.js 缓存实践
2018/06/25 Javascript
实例分析Array.from(arr)与[...arr]到底有何不同
2019/04/09 Javascript
JavaScript实现五子棋游戏的方法详解
2019/07/08 Javascript
python写的ARP攻击代码实例
2014/06/04 Python
Python 3.8新特征之asyncio REPL
2019/05/28 Python
pytorch 修改预训练model实例
2020/01/18 Python
python dumps和loads区别详解
2020/02/04 Python
python实现单机五子棋
2020/08/28 Python
加拿大知名的国际儿童品牌:Hatley
2016/11/09 全球购物
李培根演讲稿
2014/05/22 职场文书
企业活动策划方案
2014/06/02 职场文书
大专生自荐书范文
2014/06/22 职场文书
少先队辅导员事迹材料
2014/12/24 职场文书
预备党员入党感想
2015/08/10 职场文书
2016年寒假家长评语
2015/10/10 职场文书
PHP命令行与定时任务
2021/04/01 PHP
redis使用不当导致应用卡死bug的过程解析
2021/07/01 Redis
postgreSQL数据库基础知识介绍
2022/04/12 PostgreSQL