python基础8

mac2026-05-19  6

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

1、客户端

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

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

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

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

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

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

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

# 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...
最新回复(0)