zoukankan      html  css  js  c++  java
  • day31——recv工作原理、高大上版解决粘包方式、基于UDP协议的socket通信

    day31

    recv工作原理

    源码解释:
    Receive up to buffersize bytes from the socket.
    接收来自socket缓冲区的字节数据,
    For the optional flags argument, see the Unix manual.
    对于这些设置的参数,可以查看Unix手册。
    When no data is available, block untilatleast one byte is available or until the remote end is closed.
    当缓冲区没有数据可取时,recv会一直处于阻塞状态,直到缓冲区至少有一个字节数据可取,或者远程端关闭。
    When the remote end is closed and all data is read, return the empty string.
    关闭远程端并读取所有数据后,返回空字符串。
    

    高大上版解决粘包方式(自定制报头)

    我们要制作固定的报头

    你现在有两段不固定长度的bytes类型,我们要固定的报头,所以

    • 你获取不固定报头的长度
    • 利用struct模块将不固定的长度转化成固定的字节数4个字节
    • 先发4个字节,再发报头数据,再发总数据
    server
    import socket
    import subprocess
    import struct
    import json
    phone = socket.socket()
    phone.bind(("127.0.0.1",8080))
    phone.listen(3)
    while 1:
        conn, addr = phone.accep()
        print(f"{addr}客户端链接了")
        while 1:
            try:
                from_client_data = conn.recv(1024)
                obj = subprocess.Popen(from_client_data.decode("utf-8"),
                                      shell = True,
                                      stdout = subprocess.PIPE,
                                      stderr = subprocess.PIPE
                                      )
                data = obj.stdout.read() + obj.stderr.read()
                data_len = len(data)
                
                # 1、自定义报头
                head_dic = {
                    "file_name": "test1",
                    "md5": 654654654654,
                    "total_size": data_len
                }
                
                # 2、json形式的报头
                head_dic_json = json.dumps(head_dic)
                
                # 3、bytes形式的报头
                head_dic_json_bytes = head_dic_json.encode("utf-8")
                
                # 4、bytes形式的报头的总字节数
                len_head_dic_json_bytes = len(head_dic_json_bytes)
                
                # 5、把报头的总字节数变成固定的4个字节
                four_head_bytes = struct.pack("i", len_head_dic_json_bytes)
                
                # 6、发送固定的4个字节
                conn.send(four_head_bytes)
                
                # 7、发送bytes形式的报头
                conn.send(head_dic_json_bytes)
                
                # 8、发送总数据
                conn.send(data)
            exctpt Exception:
                print(f"{addr}客户端关闭!")
                break
        conn.close()
    phone.close()                       
    
    client
    import socket
    import struct
    import json
    phone = socket.socket()
    phone.connect(("127.0.0.1", 8080))
    while 1:
        data = input("请输入>>>")
        if not data:
            print("输入内容不为空!")
            continue
        phone.send(data.encode("utf-8"))
        if data.upper() == "Q":
            print("通信关闭")
            break
        
        # 1、获取报头的固定4个字节
        four_head_bytes = phone.recv(4)
        
        # 2、把固定的4个字节变成bytes形式的报头的总字节数
        len_head_dic_json_bytes = struct.unpack("i", four_head_bytes)[0]
        
        # 3、获取到bytes形式的报头
        head_dic_json_bytes = phone.recv(len_head_dic_json_bytes)
        
        # 4、获取json形式的报头
        head_dic_json = head_dic_json_bytes.decode("utf-8")
        
        # 5、获取报头
        dic = json.loads(head_dic_json)
        
        # 6、获取总数据长度
        data_len = dic["total_size"]
        
        # 7、定义一个空字节
        data_deposit = b""
        
        # 8、循环获取总数据
        while len(data_deposit) < data_len:
            data_deposit += phone.recv(1024)
        # 把总数据转成源数据
        print(data_deposit.decode("gbk"))
    phone.close()
    

    基于UDP协议的socket通信

    多人在服务器聊天

    server

    import socket
    server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    server.bind(("127.0.0.1", 9000))
    
    while True:
        conn, addr = server.recvfrom(1024)
        print(f"来自{addr}的消息:{conn.decode('utf-8')}")
    

    client

    import socket
    client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    
    while True:
        data = input(">>>")
        client.sendto(data.encode("utf-8"), ("172.0.0.1", 8080))
    
    服务器与多人聊天

    server

    import socket
    server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    server.bind(("127.0.0.1", 9000))
    
    while True:
        conn, addr = server.recvfrom(1024)
        print(f"来自{addr}的消息:{conn.decode('utf-8')")
        
        data = input(">>>")
        server.sendto(data.encode("utf-8"), addr)
    

    client

    import socket
    client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    
    while True:
        data = input(">>>")
        client.sendto(data.encode("utf-8"), ("127.0.0.1", 9000))
    
        conn, addr = client.recvfrom(1024)
        print(f"来之{addr}的消息:{conn.decode('utf-8')}")
    
  • 相关阅读:
    现在的技术QQ群为什么都变成了这样?效率高也是有弊端的?
    【php】php中mail()不可用,php中sendmail不能用的解决方法
    Cannot validate since no PHP executable is set. Use the setting 'php.validate.executablePath' to configure the PHP executable.无法使用PHP可执行的设置。设置php.validate。executablePath配置PHP可执行文件。
    20150907自动化测试之Appinum For Android(前篇)
    [摘]关于目标管理
    婚恋网站应该有视频功能
    GIS的双屏显示模式是一个实用的创新
    移动产品将越分越细
    基于开源GIS软件的电子政务地理信息应用解决方案
    手机长途话费应再降!
  • 原文地址:https://www.cnblogs.com/NiceSnake/p/11385871.html
Copyright © 2011-2022 走看看