• 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
  • 相关阅读:
    Spring Boot 学习(一) 快速搭建SpringBoot 项目
    @RunWith和 SpringJUnit4ClassRunner ---->junit4和Spring一起使用
    Spring Boot的SpringApplication类详解
    @SpringBootApplication的使用
    使用阿里云搭建个人博客
    @Controller和@RestController的区别?
    蚂蚁金服开发文档中心
    Logger.getLogger()和LogFactory.getLog()的区别
    SimpleDateFormat使用详解
    SpringBoot整合RabbitMQ实现微服务间的异步消息沟通
  • 原文地址:https://www.cnblogs.com/xuanxuanlove/p/9743442.html
Copyright © 2020-2023  润新知