python基础8_2-socket(二)实现简单的ssh客户端和服务器

该篇用socket来模拟终端命令的实现。通过客户端来发送指令,服务器接收到指令后,执行指令,将执行后的结果发送给客户端,客户端接收到指令之后,打印在屏幕上。

1、客户端

  1. 生成socket连接对象
  2. 建立连接
  3. 输入要发送的"指令"信息
  4. 判断发送内容是否为空。是,重新输入;否,发送信息到服务器
  5. 接收服务器发回来的信息,打印

由于客户端一次性接收信息的大小有限,所以如果发回来的信息过大,客户端只能够接收一部分的信息,剩下的信息会暂存在服务器的缓存区里,得等到下一次交互的时候才会将剩余的部分发过来,这就导致了下一次交互的指令收到的却是上一次指令的结果。
所以按照上面的流程难以实现,所以我们现在修改下上面的流程:

  1. 生成socket连接对象
  2. 建立连接
  3. 输入要发送的"指令"
  4. 判断输入内容是否为空。是,重新输入;否,发送信息到服务器
  5. 接收服务器发过来的信息,该信息的内容是服务器将要发送的返回结果的大小
  6. 设置循环直到接收的数据大小>=服务器告诉我们的大小,结束接收
  7. 打印

下面是客户端具体的实现代码:

# Author: Mr.Xue
# 2019.10.29
# socket_ssh_client.py

import socket

client = socket.socket() # 声明socket类型,同时生成socket连接对象
client.connect(('localhost', 6961)) # 开始连接,ip地址为本地,端口号为6961
while True:
	msg = input(">>").strip() # 输入要发送的信息
	#print(len(msg)) 
	if len(msg) == 0: continue # 判断输入的信息是否为空,如果空,重新输入
	client.send(msg.encode("utf-8")) # 发送信息到服务器
	cmd_res_size = client.recv(1024) # 接收服务器将发送过来的文件的大小
	print("命令结果的大小:",cmd_res_size.decode())
	client.send("准备好接收了".encode("utf-8"))
	receive_size = 0 # 记录接收数据的大小
	receive_data = b'' # 记录接收数据的变量
	while receive_size < int(cmd_res_size.decode()): #判断接收到的大小和服务器计算出来的大小进行比较
		data = client.recv(1024) # 接收服务器发过来的信息
		receive_size += len(data)
		receive_data += data
	else:
		print("cmd_res receive done...", receive_size)
		print(receive_data.decode()) # 打印服务器发来的信息
client.close() # 最后,关闭客户端

2、服务器
服务器的实现就比较简单了,唯一的难点就是怎么执行客户端发来的"指令"信息生成结果,实现的流程应如下所示:

  1. 生成socket连接对象
  2. 绑定要监听端口
  3. 监听
  4. 等待客户端的连接
  5. 接收客户端信息
  6. 处理接收到的信息
  7. 将处理后的结果发回给客户端

服务器具体实现代码如下:

# Author: Mr.Xue
# 2019.10.29
#socket_ssh_server.py

import socket, os

server = socket.socket() # 声明socket类型,同时生成socket连接对象
server.bind(('localhost', 6961)) # 绑定要监听端口
server.listen(3) # 监听
print("我要等电话了")
while True:
	print("wait1...")
	conn, addr = server.accept() # 等待电话打进来
	# conn就是客户端连过来而在服务器端为其生成的一个连接实例
	print(conn, addr)
	print("电话来了")
	while True:
		print("wait2...")
		data = conn.recv(1024) # 等待数据过来并接收
		if not data: # 如果没有数据,说明有一个客户端离线
			print("lost a link...")
			break
		print("执行指令", data)
		cmd_res = os.popen(data.decode()).read() # 接收字符串,执行结果也是字符串
		print("before send...", len(cmd_res))
		if len(cmd_res) == 0:
			cmd_res = "cmd_res has no output..."
		conn.send(str(len(cmd_res.encode())).encode("utf-8"))
		con = conn.recv(1024) # 防止粘包
		print("zhun bei hao fa song")
		conn.send(cmd_res.encode("utf-8"))
		print("send done")
server.close() # 关闭服务器

服务器端的实现代码中用os模块的popen()函数执行指令;服务器端还预防了粘包的发生。

3、测试效果

先启动服务器

xue@xue-MacBookAir:~/python_learn$ python3 socket_ssh_server.py 
我要等电话了
wait1...

服务器启动之后,启动客户端

client

xue@xue-MacBookAir:~/python_learn$ python3 socket_ssh_client.py 
>>

server

xue@xue-MacBookAir:~/python_learn$ python3 socket_ssh_server.py 
我要等电话了
wait1...
<socket.socket fd=4, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 6961), raddr=('127.0.0.1', 48694)> ('127.0.0.1', 48694)
电话来了
wait2...

之后客户端发送指令,服务器返回结果

client

>>ifconfig
8
命令结果的大小: 1001
cmd_res receive done... 1001
lo        Link encap:本地环回  
          inet 地址:127.0.0.1  掩码:255.0.0.0
          inet6 地址: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  跃点数:1
          接收数据包:22767 错误:0 丢弃:0 过载:0 帧数:0
          发送数据包:22767 错误:0 丢弃:0 过载:0 载波:0
          碰撞:0 发送队列长度:1000 
          接收字节:3111413 (3.1 MB)  发送字节:3111413 (3.1 MB)

wlp3s0    Link encap:以太网  硬件地址 c8:69:cd:b6:29:1e  
          inet 地址:192.168.0.118  广播:192.168.0.255  掩码:255.255.255.0
          inet6 地址: fe80::30d3:2cb7:d774:13bb/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  跃点数:1
          接收数据包:1533623 错误:0 丢弃:0 过载:0 帧数:678870
          发送数据包:1107983 错误:15981 丢弃:0 过载:0 载波:0
          碰撞:0 发送队列长度:1000 
          接收字节:1597160255 (1.5 GB)  发送字节:246097859 (246.0 MB)
          中断:18 


>>

server

xue@xue-MacBookAir:~/python_learn$ python3 socket_ssh_server.py 
我要等电话了
wait1...
<socket.socket fd=4, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 6961), raddr=('127.0.0.1', 48694)> ('127.0.0.1', 48694)
电话来了
wait2...
执行指令 b'ls'
before send... 1052
zhun bei hao fa song
send done
wait2...
执行指令 b'ifconfig'
before send... 767
zhun bei hao fa song
send done
wait2...

发送一条不存在的指令看看

client

>> nonono
6
命令结果的大小: 24
cmd_res receive done... 24
cmd_res has no output...
>>

server

xue@xue-MacBookAir:~/python_learn$ python3 socket_ssh_server.py 
我要等电话了
wait1...
<socket.socket fd=4, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 6961), raddr=('127.0.0.1', 48694)> ('127.0.0.1', 48694)
电话来了
wait2...
执行指令 b'ls'
before send... 1052
zhun bei hao fa song
send done
wait2...
执行指令 b'ifconfig'
before send... 767
zhun bei hao fa song
send done
wait2...
执行指令 b'nonono'
/bin/sh: 1: nonono: not found
before send... 0
zhun bei hao fa song
send done
wait2...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值