• DAY 32 UDP协议、Socketserver模块,并发编程基础


    一.粘包现象

      1.为什么会出现粘包现象

        1.只有在TCP协议中才会出现粘包现象,因为TCP协议是流式协议

        2.TCP协议的特点是将数据量小、时间间隔比较短的数据一次性打包发送

        3.粘包现象的本质是因为不知道需要接受的数据的长短

      2.如何解决粘包问题

        1.发送数据直接先告诉对方数据量的大小

        2.利用struct模块定制我们自己的消息传输协议

      3.基于TCP发送大文件示例

    # 客户端
    import struct
    import json
    import socket
    import os
    
    client = socket.socket()
    client.connect(('127.0.0.1', 8080))
    
    file_size = os.path.getsize(r'/Users/jiboyuan/PycharmProjects/aboutsocket/10 解决粘包问题终极版.mp4')
    file_path = r'/Users/jiboyuan/PycharmProjects/aboutsocket/10 解决粘包问题终极版.mp4'
    data_dic = {
        'file_name': '澳门最大线上赌场开业啦.mp4',
        'file_size': file_size
    }
    header_json = json.dumps(data_dic)
    header_bytes = header_json.encode('utf-8')
    # 制作字典的报头
    header = struct.pack('i', len(header_bytes))
    # 发送报头
    client.send(header)
    # 发字典数据
    client.send(header_bytes)
    # 打开文件发送文件数据
    with open(file_path,'rb') as f:
        for line in f:
            client.send(line)
    
    # 服务端
    import socket
    import json
    import struct
    
    server = socket.socket()
    server.bind(('127.0.0.1', 8080))
    server.listen(5)
    
    while True:
        conn, addr = server.accept()
        while True:
            try:
                header = conn.recv(4)
                if len(header) == 0:break
                dic_len = struct.unpack('i', header)[0]
    
                real_dic = json.loads(conn.recv(dic_len).decode('utf-8'))
                print(real_dic)
                file_name = real_dic.get('file_name')
                file_size = real_dic.get('file_size')
                recv_size = 0
                with open(file_name, 'wb') as f:
                    while recv_size < file_size:
                        recv_data = conn.recv(1024)
                        f.write(recv_data)
                        recv_size += len(recv_data)
            except ConnectionResetError:
                break

    二.UDP协议

      1.UDP协议的优点

       1.UDP协议客户端允许发空

       2.UDP协议不会粘包

       3.UDP协议服务端不存在的情况下,客户端照样不会报错

       4.UDP协议支持并发

      2.UDP协议的要求

       1.UDP协议也叫数据报协议,发送的消息都带有数据头

       2.UDP的服务端不需要进行监听也不需要建立连接

       3.服务端启动后只能被动的等待客户端发送消息,发送消息时要带上服务端地址

       4.服务端在回复消息的时候,也需要带上客户端的地址、

      示例:

    # 服务端
    import socket
    
    server = socket.socket(type=socket.SOCK_DGRAM)
    server.bind(('127.0.0.1', 8080))
    
    msg, addr = server.recvfrom(1024)
    print(msg.decode('utf-8'))
    server.sendto(b'hello', addr)
    
    server.close()
    
    #客户端
    import socket
    
    client = socket.socket(type=socket.SOCK_DGRAM)
    server_addr = ('127.0.0.1', 8080)
    
    client.sendto(b'hello server baby!', server_addr)
    msg, addr = client.recvfrom(1024)
    print(msg, addr)

    3.UDP协议特点

       1.无链接,类似于发短信,发了就行爱回不回没有任何关系

       2.将服务端关闭,客户端依旧能够发数据,不需要考虑服务端能不能收到

      4.基于UDP实现简易版本QQ

    # 服务端
    import socket
    
    server = socket.socket(type=socket.SOCK_DGRAM)
    server.bind(('127.0.0.1', 8080))
    while True:
        msg, addr = server.recvfrom(1024)
        print(addr)
        print(msg.decode('utf-8'))
        info = input('>>>:').encode('utf-8')
        server.sendto(info, addr)
    
    server.close()
    
    # 多个客户端
    import socket
    
    client = socket.socket(type=socket.SOCK_DGRAM)
    server_addr = ('127.0.0.1', 8080)
    
    while True:
        info = input('>>>:')
        info = ('来自客户端1的消息:%s'%info).encode('utf-8')  # 改中文备注即可
        client.sendto(info, server_addr)
        msg, addr = client.recvfrom(1024)
        print(msg.decode('utf-8'), addr)
    
    client.close()

    三.socketserver模块(让TCP也能支持并发)

    # TCP socketserver使用
    import socketserver
    class MyTcpServer(socketserver.BaseRequestHandler):
        def handle(self):
            while True:
                try:
                    data = self.request.recv(1024)  # 对于tcp,self.request相当于conn对象
                    if len(data) == 0:break
                    print(data)
                    self.request.send(data.upper())
                except ConnectionResetError:
                    break
    if __name__ == '__main__':
        server = socketserver.ThreadingTCPServer(('127.0.0.1',8081),MyTcpServer)
        server.serve_forever()
    
    # UDP socketserver使用
    import socketserver
    
    
    class MyUdpServer(socketserver.BaseRequestHandler):
        def handle(self):
            while True:
                data, sock = self.request
                print(data)
                sock.sendto(data.upper(), self.client_address)
    
    
    if __name__ == '__main__':
        server = socketserver.ThreadingUDPServer(('127.0.0.1', 8080), MyUdpServer)
        server.serve_forever()

    四.并发编程

      1.操作系统的发展史

       输入输出设备>>>:IO操作即(input和output)

       手工操作穿孔卡片

       批处理(磁带)

       脱机批处理系统

       一步步的优化,其实都是在提高计算机CPU利用率的问题(问题在于时串行并且没有空间上的复用)

      2.多道技术的产生

       解决cpu在执行程序,遇到io时,不干活的情况

       串行:一个程序完完整整的运行完毕,才能运行下一个程序

       并发:看上去像同时运行

       多道技术:

        1.空间上的复用(多个程序共一套硬件设备,它是多道技术实现时间上的复用的基础,不然还要去硬盘读数据)

        2.时间上的复用(单个cpu的电脑上,起多个应用程序。cpu快速切换,给人的感觉是同时运行)

        3.一个任务占用cpu时间过长或被操作系统强行剥夺走cpu的执行权限(比起串行效率反而降低)

        4.一个任务执行过程中遇到io操作,也会被操作系统强行剥夺走cpu的执行权限(比起串行效率提高)

  • 相关阅读:
    VirtualBox 创建com对象失败
    大数据(十)
    HITCON 2014 已開始征求投稿计划书
    CSS
    工具
    工具
    Linux
    Python
    JavaScript
    JavaScript
  • 原文地址:https://www.cnblogs.com/zhengyuli/p/10823302.html
Copyright © 2020-2023  润新知