zoukankan      html  css  js  c++  java
  • 24、解决粘包问题的方法、UDP套接字简单示例、多并发问题

    一、解决粘包问题的方法(简单版)

    • 服务端
    from socket import *
    from subprocess import PIPE, Popen
    import struct
    
    server = socket(AF_INET, SOCK_STREAM)
    server.bind(('127.0.0.1', 8000))
    server.listen(5)
    
    while True:
        conn, client_addr = server.accept()
        print(client_addr)
    
        while True:  # 通信循环
            try:
                cmd = conn.recv(8096)
                if len(cmd) == 0:  # 针对于linux系统
                    break
                obj = Popen(cmd.decode('utf-8'),
                            shell=True,
                            stderr=PIPE,
                            stdout=PIPE, )
                res1 = obj.stdout.read()
                res2 = obj.stderr.read()
                total_size = len(res1) + len(res2)
    
                # 先把数据的长度给发过去,长度为4
                header = struct.pack('i', total_size)
                conn.send(header)
    
                # 再发送真正的数据
                conn.send(res2)  # 利用TCP协议的特性
                conn.send(res1)  # nagle算法规定,TCP协议会将数据量较小、
                # 时间间隔短的数据合并为一条发送给客户端
            except Exception:
                break
        conn.close()  # 异常断开后回收资源
    
    • 客户端
    from socket import *
    from subprocess import PIPE, Popen
    import struct
    
    client = socket(AF_INET, SOCK_STREAM)
    client.connect(('127.0.0.1', 8000))
    
    while True:
        cmd = input('>>>:').strip()
        if len(cmd) == 0:
            continue
        client.send(cmd.encode('utf-8'))
    
        # 先接收数据的长度
        header = client.recv(4)
        total_size = struct.unpack('i', header)[0]  # 提取出字节长度
    
        # 接收真正的数据
        recv_size = 0
        res = b''
        while recv_size < total_size:
            data = client.recv(1024)
            recv_size += len(data)
            res += data
        print(res.decode('gbk'))
    

    二、解决粘包问题的方法(优化版)

    • 服务端
    import json
    from socket import *
    import struct
    from subprocess import PIPE, Popen
    
    server = socket(AF_INET, SOCK_STREAM)
    server.bind(('127.0.0.1', 8000))
    server.listen(5)
    
    while True:  # 链接循环
        conn, client_addr = server.accept()
        print(client_addr)
    
        while True:  # 通信循环
            try:
                cmd = conn.recv(8096)
                if len(cmd) == 0:
                    break
                obj = Popen(cmd.decode('utf-8'),
                            shell=True,
                            stdout=PIPE,
                            stderr=PIPE)
                res1 = obj.stdout.read()
                res2 = obj.stderr.read()
    
                header_dic = {
                    'filename': 'a.txt',
                    'total_size': len(res1) + len(res2),
                    'md5': 'qwe165qwqwe65456qw5'
                }
                header_json = json.dumps(header_dic)
                header_bytes = header_json.encode('utf-8')
    
                # 先发四个字节
                conn.send(struct.pack('i', len(header_bytes)))
                # 再发报头字典
                conn.send(header_bytes)
    
                # 最后发真正的数据
                conn.send(res1)
                conn.send(res2)
            except Exception:
                break
        conn.close()  # 关闭窗口来回收资源
    
    
    • 客户端
    from socket import *
    import struct
    import json
    
    client = socket(AF_INET, SOCK_STREAM)
    client.connect(('127.0.0.1', 8000))
    
    while True:
        cmd = input('>>>: ').strip()
        if len(cmd) == 0:
            continue
        client.send(cmd.encode('utf-8'))
    
        # 先接收四个字节,提取header_bytes的长度
        header_bytes_len = struct.unpack('i', client.recv(4)[0])
        # 再收header_bytes,提取header_dic
        header_bytes = client.recv(header_bytes_len)
        header_json = header_bytes.decode('utf-8')
        header_dic = json.loads(header_json)
        print(header_json)
        total_size = header_dic['total_size']
    
        # 再接收真正的数据
        recv_size = 0
        res = b''
        while recv_size < total_size:
            data = client.recv(1024)
            recv_size += len(data)
            res += data
    
        print(res.decode('gbk'))
    
    

    三、基于UDP套接字的编写

    • 服务端
    import socket
    
    server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  # 造手机
    server.bind(('127.0.0.1', 8000))  # 需要绑定,不许要监听
    while True:  # 通信循环
        data, client_addr = server.recvfrom(1024)
        # 解压赋值(文本,发送端的端口号)
        print(data)
        server.sendto(data.upper(), client_addr)
    
    • 客户端
    from socket import *
    
    client = socket(AF_INET, SOCK_DGRAM)  # 造手机
    while True:  # 输入循环
        msg = input('输入:').strip()
        client.sendto(msg.encode('utf8'), ('127.0.0.1', 8000))
        # sendto(发送内容二进制,接收端口)
        data, client_addr = client.recvfrom(1024)
        # 解压赋值(接收的文本,端口)
        print(data.decode('utf-8'))
    
    • UDP协议一般不会用于大数据的传输
    • UDP套接字虽然没有粘包的问题,但是不能代替TCP套接字,因为UDP协议有一个缺陷,如果数据发送的途中,数据丢失,则数据就丢失了,而TCP协议则不会有这种缺陷,因此一般的UDP套接字用户无关紧要的数据发送,例如QQ、微信聊天等.

    四、socketserver模块

    • 基本使用框架
    import socketserver
    
    
    class MyHandler(socketserver.BaseRequestHandler):
        # 通信循环
        def handle(self):  # 调用的话以上不变
            # data = self.request.recv(1024)  # self.recv(1024)
            # print(data)
            # self.request.send(data.upper())
    
            if __name__ == '__main__':
                server = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), MyHandler, bind_and_activate=True)
                server.serve_forever()
    
    
    • 多并发——服务端
    # 同一时刻有多个人在接听
    import socketserver
    import json
    from subprocess import Popen, PIPE
    import struct
    
    
    class MyHandler(socketserver.BaseRequestHandler):
        # 通信循环
        def handle(self):  # 调用的话以上不变
            # data = self.request.recv(1024)  # self.recv(1024)
            # print(data)
            # self.request.send(data.upper())
            try:
                cmd = self.request.recv(8096)
                obj = Popen(cmd.decode('utf-8'),
                            shell=True,
                            stdout=PIPE,
                            stderr=PIPE,
                            )
    
                res1 = obj.stdout.read()
                res2 = obj.stderr.read()
    
                header_dic = {
                    'filename': "a.txt",
                    'total_size': len(res1) + len(res2),
                    'md5': '123dfsfsaf123213'
                }
    
                header_json = json.dumps(header_dic)
                header_bytes = header_json.encode('utf-8')
    
                # 先发4个字节
                self.request.send(struct.pack('i', len(header_bytes)))
                # 再发报头字典
                self.request.send(header_bytes)
    
                # 最后发送真正的数据
                self.request.send(res1)
                self.request.send(res2)
            except Exception:
                self.request.close()
    
    
    # 使用socketserver的连接循环(并发),但是使用了自己的通信循环
    
    if __name__ == '__main__':
        server = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), MyHandler, bind_and_activate=True)
        server.serve_forever()
    
    # 调用的话只需要将conn改成self.request即可
    
    
    • 多并发——客户端1
    from socket import *
    import struct
    import json
    
    client = socket(AF_INET, SOCK_STREAM)
    client.connect(('127.0.0.1', 8080))
    
    while True:
        cmd = input(">>>: ").strip()
        if len(cmd) == 0:
            continue
        client.send(cmd.encode('utf-8'))
    
        # 先收4个字节,提取header_bytes的长度
        header_bytes_len = struct.unpack('i', client.recv(4))[0]
    
    
        # 再收header_bytes,提取header_dic
        header_bytes = client.recv(header_bytes_len)
        header_json = header_bytes.decode('utf-8')
        header_dic = json.loads(header_json)
    
        print(header_dic)
    
        total_size = header_dic['total_size']
    
        # 再接收真正的数据
        recv_size = 0
        res = b''
        while recv_size < total_size:
            data = client.recv(1024)
            recv_size += len(data)
            res += data
    
        print(res.decode('gbk'))
    
    • 多并发——客户端2
    from socket import *
    import struct
    import json
    
    client = socket(AF_INET, SOCK_STREAM)
    client.connect(('127.0.0.1', 8080))
    
    while True:
        cmd = input(">>>: ").strip()
        if len(cmd) == 0:
            continue
        client.send(cmd.encode('utf-8'))
    
        # 先收4个字节,提取header_bytes的长度
        header_bytes_len = struct.unpack('i', client.recv(4))[0]
    
    
        # 再收header_bytes,提取header_dic
        header_bytes = client.recv(header_bytes_len)
        header_json = header_bytes.decode('utf-8')
        header_dic = json.loads(header_json)
    
        print(header_dic)
    
        total_size = header_dic['total_size']
    
        # 再接收真正的数据
        recv_size = 0
        res = b''
        while recv_size < total_size:
            data = client.recv(1024)
            recv_size += len(data)
            res += data
    
        print(res.decode('gbk'))
    
    
  • 相关阅读:
    Mac上的USB存储设备使用痕迹在新版操作系统有所变化
    Beware of the encrypted VM
    A barrier for Mobile Forensics
    Second Space could let suspect play two different roles easily
    Take advantage of Checkra1n to Jailbreak iDevice for App analysis
    Find out "Who" and "Where"
    Where is the clone one and how to extract it?
    Downgrade extraction on phones running Android 7/8/9
    高版本安卓手机的取证未来
    How to extract WeChat chat messages from a smartphone running Android 7.x or above
  • 原文地址:https://www.cnblogs.com/zhaokunhao/p/14298301.html
Copyright © 2011-2022 走看看