1. subprocess模块
import subprocess res=subprocess.Popen('dir',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) print(res.stdout.read().decode("gbk")) # windows 上的编码是gbk print(res.stderr.read().decode('gbk'))
运行结果:
2. 基于TCP实现远程执行命名(server端下发命令,client端执行命令)
# server.py import socket sk=socket.socket() sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) sk.bind(('127.0.0.1',8080)) sk.listen() conn,addr=sk.accept() while True: cmd=input(">>>") # 服务端下发的命令 conn.send(bytes(cmd.encode('utf-8'))) ret=conn.recv(1024).decode("utf-8") print(ret) conn.close() sk.close()
# client.py import socket import subprocess sk=socket.socket() sk.connect(('127.0.0.1',8080)) while True: cmd=sk.recv(1024) print(cmd.decode("utf-8")) # 打印服务端发送过来的命名(字节类型转为utf-8的) res=subprocess.Popen(cmd.decode('gbk'),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) ret1="stdout:"+ res.stdout.read().decode("gbk") # read()的结果是bytes类型 decode()(因为是windows系统得用gbk解码)解码之后得到的是字符串 sk.send(bytes(ret1.encode("utf-8"))) # 发送时需要字节类型,这里把字符串类型的ret1 再encode成utf-8格式 服务端接收到之后可以按照utf_8解码 ret2="stderr:"+ res.stderr.read().decode('gbk') sk.send(bytes(ret2.encode("utf-8"))) sk.close()
运行结果:
其实会发现使用TCP实现远程执行命令,server端发送命令,client端执行完命令之后返回,会出现一条命令太大,server端分很多次才接受完,还有可能会出现stdout 和 stderr一起打印的情况,这种数据包接收时发送混乱的现象称为黏包现象
3. 基于UDP实现远程执行命令(server端下达命令,client端执行命令)
# server.py import socket sk=socket.socket(type=socket.SOCK_DGRAM) # 使用UDP时 socket.socket()需要传个参数 sk.bind(('127.0.0.1',8080)) # 仍然需要绑定一个IP和端口号,但是不需要监听(listen)和连接(accept) ret,addr=sk.recvfrom(1024) # 使用UDP server在和client端通信时,服务端需要先接收!! 这里ret没什么用(因为是server端下发命令),主要是获得客户端的地址 while True: cmd=input(">>>") # server端下发的命令 sk.sendto(bytes(cmd.encode("utf-8")),addr) # 传输时都需要转化为bytes类型,UDP 使用sendto()除了要发送的消息还需要写上需要通信的客户端的地址 ret,addr=sk.recvfrom(1024) # 接收来自客户端的消息,还会得到发消息来的客户端的地址 print(ret.decode("utf-8")) # 把传输的消息(bytes类型) 按照utf-8 decode一下 sk.close()
# client.py import socket import subprocess sk=socket.socket(type=socket.SOCK_DGRAM) addr=('127.0.0.1',8080) # 使用UDP协议的client需要指定要连接的服务器的IP地址和端口号,写成元组形式 sk.sendto(bytes("hello".encode("utf-8")),addr) # 使用UDP的client需要先发送,因为server端需要先接收 while True: cmd,addr=sk.recvfrom(1024) # 客户端收到来自服务器的命令cmd(bytes类型)以及服务器的地址 print(cmd.decode("utf-8")) # 把bytes类型的消息先解码 res=subprocess.Popen(cmd.decode('gbk'),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) # 因为subprocess.Popen("dir",shell=True,wtdout=subprocess.PIPE,stderr=subprocess.PUPE) # 中的'dir'就是字符串类型,所以需要把cmd这个bytes类型先解码(windows上的命令按照gbk解码) ret1="stdout:"+ res.stdout.read().decode("gbk") # res.read()得到字节类型的,decode("gbk")先把字节类型的解码成字符串,好完成字符串拼接,客户端发送给server端有个区分标识 sk.sendto(bytes(ret1.encode('utf-8')),addr) # 把刚才拼接的字符串,再按照utf-8 encode成bytes类型方便传输 ret2=res.stderr.read().decode('gbk') sk.sendto(bytes(ret2.encode("utf-8")),addr) sk.close()
运行结果:
所以使用基于UDP协议的server端和client端通信,client执行server端发来的命令时不会造成黏包现象,但是会造成数据的丢失,所以UDP协议是不可靠的,不面向连接的~
4. 作业----实现网盘的上传下载
客户端登录,把用户名和密码信息传给服务器端,服务器端确认信息之后,可以上传下载;
客户端选择上传or 下载:
上传: 则选择要上传的文件路径,在server端创建一个同名文件;
下载: 则选择要下载的文件路径(server端的路径),选择在client端创建一个同名的空文件;