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常用的爬虫技巧总结
Mar 28 Python
浅析Python 中整型对象存储的位置
May 16 Python
Python多线程扫描端口代码示例
Feb 09 Python
Pandas读取MySQL数据到DataFrame的方法
Jul 25 Python
python 切换root 执行命令的方法
Jan 19 Python
更新修改后的Python模块方法
Mar 03 Python
python实现最小二乘法线性拟合
Jul 19 Python
使用Tensorflow实现可视化中间层和卷积层
Jan 24 Python
python安装后的目录在哪里
Jun 21 Python
如何利用python 读取配置文件
Jan 06 Python
Pycharm 跳转回之前所在页面的操作
Feb 05 Python
python机器学习创建基于规则聊天机器人过程示例详解
Nov 02 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笔记之:文章中图片处理的使用
2013/04/26 PHP
CentOS6.5 编译安装lnmp环境
2014/12/21 PHP
PHP中PDO连接数据库中各种DNS设置方法小结
2016/05/13 PHP
针对多用户实现头像上传功能PHP代码 适用于登陆页面制作
2016/08/17 PHP
把textarea中字符串里含有的回车换行替换成&amp;lt;br&amp;gt;的javascript代码
2007/04/20 Javascript
JavaScript去掉空格的方法集合
2010/12/28 Javascript
JQUERY的属性选择符和自定义选择符使用方法(二)
2011/04/07 Javascript
Javascript alert消息换行的方法
2013/08/07 Javascript
js判断滚动条是否已到页面最底部或顶部实例
2014/11/20 Javascript
JavaScript中的立即执行函数表达式介绍
2015/03/15 Javascript
最简单的JavaScript验证整数、小数、实数、有效位小数正则表达式
2015/04/17 Javascript
JS实现网页顶部向下滑出的全国城市切换导航效果
2015/08/22 Javascript
jQuery新窗口打开外链接
2016/07/21 Javascript
JS使用正则表达式过滤多个词语并替换为相同长度星号的方法
2016/08/03 Javascript
AngularJS 自定义过滤器详解及实例代码
2016/09/14 Javascript
KnockoutJS 3.X API 第四章之表单textInput、hasFocus、checked绑定
2016/10/11 Javascript
Bootstrap优化站点资源、响应式图片、传送带使用详解3
2016/10/14 Javascript
动态创建Angular组件实现popup弹窗功能
2017/09/15 Javascript
form表单数据封装成json格式并提交给服务器的实现方法
2017/12/14 Javascript
Vue实现内部组件轮播切换效果的示例代码
2018/04/07 Javascript
jquery判断滚动条距离顶部的距离方法
2018/09/05 jQuery
使用JavaScript破解web
2018/09/28 Javascript
layui 实现table翻页滚动条位置保持不变的例子
2019/09/05 Javascript
基于Python列表解析(列表推导式)
2018/06/23 Python
Python绘图Matplotlib之坐标轴及刻度总结
2019/06/28 Python
Python考拉兹猜想输出序列代码实践
2019/07/05 Python
浅析Python 引号、注释、字符串
2019/07/25 Python
python实现身份证实名认证的方法实例
2019/11/08 Python
Python3.7下安装pyqt5的方法步骤(图文)
2020/05/12 Python
python之语音识别speech模块
2020/09/09 Python
Python约瑟夫生者死者小游戏实例讲解
2021/01/04 Python
详解HTML5 window.postMessage与跨域
2017/05/11 HTML / CSS
如何填写个人简历自我评价
2013/12/10 职场文书
公共场所标语
2014/06/30 职场文书
幼儿园保育员责任书
2014/07/22 职场文书
行政处罚听证告知书
2015/07/01 职场文书