【Python之旅】第五篇(四):基于Python Sockct多线程的简版SSH程序

简介:

    还是继续延续篇五中前三节的例子,通过对代码的修修补补,把它改成一个可以在连接后就能在Client端执行Server端命令的程序,所以就有点类似于SSH连接程序了。

    至于还是用前面的例子来改嘛,是因为上课也一直这么干,而且老师也讲得非常不错,自己吸收后也作为一个学习的记录吧,因为确实是非常不错的!

    之所以能对前面的例子如这样的修改,应当有这样的思想:前面的例子中,Server端能够返回Client端输入的字符串,那么如果Client端输入的是Linux的shell命令,Server端是否可以执行这些命令然后返回执行的结果?

    所以是基于这样的思想来进行对前面例子的改进的,达到这样的效果,需要其它一些模块的支持,当然也需要在细节上做一些改进,下面给出的代码中都会有说比较详细的说明。

    就看看这个简版的SSH程序是个什么样的东东吧。


Server端程序代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import  SocketServer
import  commands    #使用其中的getstatusoutput()函数,让Server端可以识别Client端发送过来的命令并执行
import  time        #主要使用其中的time.sleep()函数,用来解决Server端发送数据的“连块”问题
 
class  MySockServer(SocketServer.BaseRequestHandler):
 
     def handle(self):
         print  'Got a new connection from' , self.client_address
         while  True:
             cmd = self.request.recv( 1024 )
             if  not cmd:
                 print  'Last connection with:' ,self.client_address
                 break
             
             cmd_result = commands.getstatusoutput(cmd)    #获取Client端的指令并执行,返回结果是一个存储两个元素的元组,第一个元素为 0 表示成功执行,第二个元素则是命令的执行结果
 
             self.request.send(str(len(cmd_result[ 1 ])))    #发送命令执行结果的大小长度,Client端要想接收任意大小的执行结果,就需要根据命令执行结果的大小来选择策略,这里需要注意的是,发送的数据是字符串,所以需要作类型转换
 
             time.sleep( 0.2 )        #睡眠 0 .2s,是为了解决“连块”的问题
 
             self.request.sendall(cmd_result[ 1 ]) #发送命令执行结果
 
if  __name__ ==  '__main__' :
     HOST =  ''
     PORT =  50007
     s = SocketServer.ThreadingTCPServer((HOST, PORT), MySockServer)
 
     s.serve_forever()


Client端程序代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import  socket
 
HOST =  '192.168.1.13'
PORT =  50007
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
 
def data_all(obj, lenth_size):
     data =  ''                 #用来存储每一次循环时socket接收的数据,解决socket大概两万多字节的缓冲瓶颈限制
     while  lenth_size !=  0 :   #如果接收的数据长度不为 0 ,开始执行接收数据处理策略
         if  lenth_size <=  4096 :    #这里以 4096 为单位块,作为每次的数据处理量大小
             data_recv = obj.recv(lenth_size)    #通过recv()接收数据
             lenth_size =  0     #通过这一步的处理,数据全部接收完毕,置lenth_size为 0 ,结束循环,完成数据的接收处理工作
         else :
             data_recv = obj.recv( 4096 )    #以 4096 为单位块,一次接收 4096 的数据量大小
             lenth_size -=  4096             #处理完一次 4096 字节的数据后,将lenth_size减去 4096
         data += data_recv                     #判断外层,用本地的data来存储接收到的数据,因为本地的data大小没有限制,所以不存在data饱和无法继续存储数据的问题,但前面socket的recv()函数一次最多只能接收的数据量大小是有限制的,这取决于socket的缓冲区大小,因此data_all函数的作用就是通过使用多次recv()函数,并且每次接收一定量的数据后就进行本地存储,直到把所有的数据都接收完毕
     return  data
 
while  True:
     user_input = raw_input( 'cmd to send:' ).strip()
     if  len(user_input) ==  0 : continue
     s.sendall(user_input)
 
     data_size =  int (s.recv( 1024 ))      #得到命令执行结果的大小长度,因为发送过来的数据是字符串,所以这里要作类型转换
     print  '\033[32;1mdata size:\033[0m' ,data_size    #打印命令执行结果的大小
     result = data_all(s, data_size)    #通过data_all函数来执行相应的数据接收处理策略
     print result                       #打印命令执行结果
 
s.close()                                  #关闭套接字


演示:

步骤1:Server端运行服务端程序

1
2
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day5$ python ssh_server5.py 
===>光标在此处处于等待状态

步骤2:Client端运行客户端程序并观察返回结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day5$ python ssh_client5.py 
cmd to send:df
data size:  502                                 ===>命令执行结果的大小
df:  "/var/lib/lightdm/.gvfs" : 权限不够        ===>命令的执行结果
文件系统           1K-块      已用    可用 已用% 挂载点
/dev/sda3         8781832    3458300  4877428    42 % /
udev               493784          4   493780     1 % /dev
tmpfs              201040        784   200256     1 % /run
none                 5120          0     5120     0 % /run/lock
none               502592        144   502448     1 % /run/shm
/dev/sda1           93207      30139    58256    35 % /boot
.host:/         162256468  152391980  9864488    94 % /mnt/hgfs
cmd to send:pwd                               ===>执行pwd命令
data size:  21
/mnt/hgfs/Python/day5
cmd to send:ls
data size:  357
[ 1 ]sec_4_ver1(单线程,非交互式)
[ 2 ]sec_4_ver2(单线程,交互式,阻塞模式一般演示)
[ 3 ]sec_4_ver3(单线程,交互式,阻塞模式进阶演示)
[ 4 ]sec_4_ver3(单线程,交互式,多并发)
client4.py
duotiao_jian_biao3.py
jian_biao2.py
my_conn1.py
server4.py
ssh_client5.py
ssh_server5.py
Thread_socket_server4.py
cmd to send:top -bn  3         ===>注意该命令的执行结果(大小)已经超出了socket的缓冲区大小,因此上面Client端中的程序代码主要就是为了解决该问题,这也是Client端的关键所在
data size:  34378              ===>该命令的执行结果大小为三万多字节,超出了socket缓冲区,socket的recv()函数是无法一次接收那么多数据的
 
……
省略输出结果
 
cmd to send:ls               ===>继续执行命令,返回结果正常
data size:  357
[ 1 ]sec_4_ver1(单线程,非交互式)
[ 2 ]sec_4_ver2(单线程,交互式,阻塞模式一般演示)
[ 3 ]sec_4_ver3(单线程,交互式,阻塞模式进阶演示)
[ 4 ]sec_4_ver3(单线程,交互式,多并发)
client4.py
duotiao_jian_biao3.py
jian_biao2.py
my_conn1.py
server4.py
ssh_client5.py
ssh_server5.py
Thread_socket_server4.py

    可以看到上面两个程序已经比较好的实现了命令执行的功能了,问题主要是集中在:

1.Server端发送数据的“连块”问题,即发送两次数据时,如果发送间隔比较短,socket会把两次发送的数据放在一起来发送,这里通过time.sleep()函数来解决。

2.socket的缓冲区大小问题,即当执行top -bn 3这样执行结果长度大的命令时,socket缓冲区一次是无法存储这么多数据的,所以只能分多次来接收数据,这样就会在Client端带来一定的问题,比如命令执行的不同步等,解决的方法是通过用循环接收的方法来进行本地存储Server端发送的数据。

    当然,如果要执行man等查询方面的命令,上面的程序也是无法做到的,所以这里说,这只是一个简版的SSH程序,作为对Python socket的学习就好了,真要用SSH的话,那还不如直接下个ssh连接软件。




本文转自 xpleaf 51CTO博客,原文链接:http://blog.51cto.com/xpleaf/1700072,如需转载请自行联系原作者

相关文章
|
13天前
|
机器学习/深度学习 数据挖掘 Python
Python编程入门——从零开始构建你的第一个程序
【10月更文挑战第39天】本文将带你走进Python的世界,通过简单易懂的语言和实际的代码示例,让你快速掌握Python的基础语法。无论你是编程新手还是想学习新语言的老手,这篇文章都能为你提供有价值的信息。我们将从变量、数据类型、控制结构等基本概念入手,逐步过渡到函数、模块等高级特性,最后通过一个综合示例来巩固所学知识。让我们一起开启Python编程之旅吧!
|
2月前
|
安全 数据处理 开发者
Python中的多线程编程:从入门到精通
本文将深入探讨Python中的多线程编程,包括其基本原理、应用场景、实现方法以及常见问题和解决方案。通过本文的学习,读者将对Python多线程编程有一个全面的认识,能够在实际项目中灵活运用。
|
13天前
|
存储 Python
Python编程入门:打造你的第一个程序
【10月更文挑战第39天】在数字时代的浪潮中,掌握编程技能如同掌握了一门新时代的语言。本文将引导你步入Python编程的奇妙世界,从零基础出发,一步步构建你的第一个程序。我们将探索编程的基本概念,通过简单示例理解变量、数据类型和控制结构,最终实现一个简单的猜数字游戏。这不仅是一段代码的旅程,更是逻辑思维和问题解决能力的锻炼之旅。准备好了吗?让我们开始吧!
|
15天前
|
并行计算 数据处理 调度
Python中的并发编程:探索多线程与多进程的奥秘####
本文深入探讨了Python中并发编程的两种主要方式——多线程与多进程,通过对比分析它们的工作原理、适用场景及性能差异,揭示了在不同应用需求下如何合理选择并发模型。文章首先简述了并发编程的基本概念,随后详细阐述了Python中多线程与多进程的实现机制,包括GIL(全局解释器锁)对多线程的影响以及多进程的独立内存空间特性。最后,通过实例演示了如何在Python项目中有效利用多线程和多进程提升程序性能。 ####
|
15天前
|
机器学习/深度学习 数据挖掘 开发者
Python编程入门:理解基础语法与编写第一个程序
【10月更文挑战第37天】本文旨在为初学者提供Python编程的初步了解,通过简明的语言和直观的例子,引导读者掌握Python的基础语法,并完成一个简单的程序。我们将从变量、数据类型到控制结构,逐步展开讲解,确保即使是编程新手也能轻松跟上。文章末尾附有完整代码示例,供读者参考和实践。
|
25天前
|
机器学习/深度学习 算法 编译器
Python程序到计算图一键转化,详解清华开源深度学习编译器MagPy
【10月更文挑战第26天】MagPy是一款由清华大学研发的开源深度学习编译器,可将Python程序一键转化为计算图,简化模型构建和优化过程。它支持多种深度学习框架,具备自动化、灵活性、优化性能好和易于扩展等特点,适用于模型构建、迁移、部署及教学研究。尽管MagPy具有诸多优势,但在算子支持、优化策略等方面仍面临挑战。
59 3
|
27天前
|
Java Unix 调度
python多线程!
本文介绍了线程的基本概念、多线程技术、线程的创建与管理、线程间的通信与同步机制,以及线程池和队列模块的使用。文章详细讲解了如何使用 `_thread` 和 `threading` 模块创建和管理线程,介绍了线程锁 `Lock` 的作用和使用方法,解决了多线程环境下的数据共享问题。此外,还介绍了 `Timer` 定时器和 `ThreadPoolExecutor` 线程池的使用,最后通过一个具体的案例展示了如何使用多线程爬取电影票房数据。文章还对比了进程和线程的优缺点,并讨论了计算密集型和IO密集型任务的适用场景。
48 4
|
27天前
|
算法 测试技术 开发者
在Python开发中,性能优化和代码审查至关重要。性能优化通过改进代码结构和算法提高程序运行速度,减少资源消耗
在Python开发中,性能优化和代码审查至关重要。性能优化通过改进代码结构和算法提高程序运行速度,减少资源消耗;代码审查通过检查源代码发现潜在问题,提高代码质量和团队协作效率。本文介绍了一些实用的技巧和工具,帮助开发者提升开发效率。
34 3
|
1月前
|
存储 人工智能 数据挖掘
Python编程入门:构建你的第一个程序
【10月更文挑战第22天】编程,这个听起来高深莫测的词汇,实际上就像搭积木一样简单有趣。本文将带你走进Python的世界,用最浅显的语言和实例,让你轻松掌握编写第一个Python程序的方法。无论你是编程新手还是希望了解Python的爱好者,这篇文章都将是你的理想起点。让我们一起开始这段奇妙的编程之旅吧!
25 3
|
2月前
|
Java 开发者
如何通过易语言多线程提升程序响应速度?
如何通过易语言多线程提升程序响应速度?
下一篇
无影云桌面