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 相关文章推荐
Python实现一个简单的MySQL类
Jan 07 Python
python实现将一个数组逆序输出的方法
Jun 25 Python
Django-Rest-Framework 权限管理源码浅析(小结)
Nov 12 Python
python linecache 处理固定格式文本数据的方法
Jan 08 Python
Python微医挂号网医生数据抓取
Jan 24 Python
python的内存管理和垃圾回收机制详解
May 18 Python
Python编程学习之如何判断3个数的大小
Aug 07 Python
python numpy数组复制使用实例解析
Jan 10 Python
Python之字典对象的几种创建方法
Sep 30 Python
python 窃取摄像头照片的实现示例
Jan 08 Python
python sleep和wait对比总结
Feb 03 Python
Python爬取你好李焕英豆瓣短评生成词云的示例代码
Feb 24 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
PHP中对数据库操作的封装
2006/10/09 PHP
Http 1.1 Etag 与 Last-Modified提高php效率
2008/01/10 PHP
PHP版自动生成文章摘要
2008/07/23 PHP
PHP中文URL编解码(urlencode()rawurlencode()
2010/07/03 PHP
基于PHP+jQuery+MySql实现红蓝(顶踩)投票代码
2015/08/25 PHP
javascript:以前写的xmlhttp池,代码
2008/05/18 Javascript
JS两种定义方式的区别、内部原理
2013/11/21 Javascript
jQuery之选项卡的简单实现
2014/02/28 Javascript
js判断当前浏览器类型,判断IE浏览器方法
2014/06/02 Javascript
jQuery使用fadein方法实现渐出效果实例
2015/03/27 Javascript
jQuery插件datepicker 日期连续选择
2015/06/12 Javascript
EasyUI加载完Html内容样式渲染完成后显示
2016/07/25 Javascript
Boostrap基础教程之JavaScript插件篇
2016/09/08 Javascript
浅析使用BootStrap TreeView插件实现灵活配置快递模板
2016/11/28 Javascript
js自定义Tab选项卡效果
2017/06/05 Javascript
详解利用 Express 托管静态文件的方法
2017/09/18 Javascript
vue 实现边输入边搜索功能的实例讲解
2018/09/16 Javascript
解析JS在获取当前月的最后一天遇到的坑
2019/08/30 Javascript
vue自定义指令和动态路由实现权限控制
2020/08/28 Javascript
详解webpack的clean-webpack-plugin插件报错
2020/10/16 Javascript
python实现代码行数统计示例分享
2014/02/10 Python
关于keras中keras.layers.merge的用法说明
2020/05/23 Python
html5中监听canvas内部元素点击事件的三种方法
2019/04/28 HTML / CSS
Lulu & Georgia官方网站:购买地毯、家具、抱枕、壁纸、床上用品等
2018/03/19 全球购物
护理专科毕业推荐信
2013/11/10 职场文书
外贸采购员岗位职责
2014/03/08 职场文书
委托书怎么写
2014/07/31 职场文书
小学生作文批改评语
2014/12/25 职场文书
先进个人推荐材料
2014/12/29 职场文书
幼儿教师小班个人总结
2015/02/05 职场文书
小人国观后感
2015/06/11 职场文书
纪检监察立案决定书
2015/06/24 职场文书
初任公务员培训心得体会
2016/01/08 职场文书
有关花店创业的计划书模板
2019/08/27 职场文书
对讲机的最大通讯距离是多少
2022/02/18 无线电
Java实战之课程信息管理系统的实现
2022/04/01 Java/Android