day8-socket实现简单的ssh
实验简述
在上一个模块,我们了解可以通过socket封装底层协议对服务器端和客户端之间进行收发消息,实现通信,那么我们可以做一个客户端连接上服务端后,让服务器执行命令,并返回结果给客户端。下面我们就来实现该功能
服务器端
import socket,os #导入模块 server = socket.socket() #创建服务器实例 server.bind(("localhost",9995)) #绑定要监听的IP地址和端口 server.listen() #监听TCP传入连接 while True: conn,addr = server.accept() #conn就是客户端连接过来在服务器端为其生成的一个连接实例(对象) print("new conn:",addr) while True: data = conn.recv(1024) #接收客户端发送来的数据 if not data: print("客户端已断开") break print("执行指令:",data.decode()) cmd_res = os.popen(data.decode()).read() #默认数据存储在I/O缓冲区 print("执行命令结果大小:",len(cmd_res)) if len(cmd_res) == 0: cmd_res= "cmd没有正确输出。。。。" conn.send(cmd_res.encode()) #发送数据到客户端(手动强制缓冲区超时去发送数据,默认等缓冲区填满再自动发送) print("发送完成!") server.close() #关闭服务器端
客户端
import socket client = socket.socket() #创建客户端实例(对象) client.connect(("localhost",9995)) #连接远程机器 while True: cmd_input = input(">>:") if len(cmd_input) == 0: continue client.send(cmd_input.encode()) #发送数据到远端 data = client.recv(1024) #从远端接收数据 print(data.decode()) client.close() #关闭客户端
执行过程
服务器端
客户端
通过以上在客户端上执行pwd命令后都能正常返回命令在服务器端执行的结果,但是当我们使用ifconfig返回的命令结果和接下来执行的ls命令时显示的结果却是上一次ifconfig没有输出完成的结果,这是为什么呢?
解析:用户第一次执行pwd命令时,命令执行的结果被存储在I/O缓冲区中,代码后面因为又执行了send操作,所以我们可以在客户端接收返回的结果,同样执行ifconfig时,服务器端将命令ifconfig执行的结果通过send全部发送到客户端(默认情况下结果存储在服务器缓冲区),而客户端因为默认情况下,一次最多只能接收1024B=1KB大小的数据,其客户端没有接收的数据存储在服务器端的I/O缓冲区,那么什么时候此缓冲区的数据能全部发送到客户端呢?
- 第一种情况:等待下一次服务器端再向客户端send数据时(手动强制缓冲区超时),只有当I/O缓冲区的数据全部发送完成,才会发送新的数据,也就是说,只有当ifconfig在I/O缓冲区里面的数据全部发送到客户端,ls执行的命令结果才会在客户端显示。
- 第二种情况:等到此缓冲区被填满后,才会触发系统调用接口,自动发送数据到客户端。
产生的问题
ifconfig命令产生的结果大小为3237B,按照客户端每次默认只能接收1024B大小的数据,那么我们如何让客户端接收全部的命令返回结果呢?
解决思路:服务器端向客户端发送数据之前,首先计算服务端执行命令的结果的大小,然后将执行命令结果的大小发送给客户端,而客户端根据结果大小使用多次循环接收,直到接收全部数据。