python学习笔记 day31 粘包现象

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端创建一个同名的空文件;

talk is cheap,show me the code
原文地址:https://www.cnblogs.com/xuanxuanlove/p/9743442.html