• Python--网络编程-----解决粘包问题-终极版


    一、服务端代码:

     1 import socket
     2 import subprocess
     3 import struct
     4 import json
     5 
     6 phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     7 # phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
     8 phone.bind(('127.0.0.1', 8081))  # 0-65535:0-1024给操作系统使用
     9 phone.listen(5)
    10 
    11 print('starting......')
    12 while True:  # 链接循环
    13     conn, client_addr = phone.accept()
    14     print(client_addr)
    15 
    16     while True:  # 通信循环
    17         try:
    18             # 1、收命令
    19             cmd = conn.recv(1024)
    20             if not cmd:  # 适用于linux操作系统
    21                 break
    22             print('客户端的数据', cmd)
    23 
    24             # 2、执行命令,拿到结果
    25             obj = subprocess.Popen(cmd.decode('utf-8'), shell=True,
    26                                    stdout=subprocess.PIPE,
    27                                    stderr=subprocess.PIPE)
    28 
    29             stdout = obj.stdout.read()
    30             stderr = obj.stderr.read()
    31             # 3、把命令的结果返回给客户端
    32             # 第一步:制作固定长度的报头
    33             header_dic = {
    34                 'filename': 'a.txt',
    35                 'md5': 'xxdxx',
    36                 'total_size': len(stdout) + len(stderr)
    37             }
    38 
    39             header_json = json.dumps(header_dic)
    40             header_bytes = header_json.encode('utf-8')
    41 
    42             # 第二步:先发送报头的长度
    43             conn.send(struct.pack('i', len(header_bytes)))
    44 
    45             # 第三步:把包头发送给客户端
    46             conn.send(header_bytes)
    47 
    48             # 第三步:再发送真实的数据
    49             conn.send(stdout)
    50             conn.send(stderr)
    51 
    52         except ConnectionResetError:  # 适用于Windows操作系统
    53             break
    54 
    55     conn.close()
    56 
    57 phone.close()

    二、客户端代码:

     1 import socket
     2 import struct
     3 import json
     4 
     5 
     6 phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     7 
     8 phone.connect(('127.0.0.1', 8081))
     9 
    10 while True:
    11     # 1、发命令
    12     cmd = input('>>:').strip()
    13     if not cmd:
    14         continue
    15     phone.send(cmd.encode('utf-8'))
    16 
    17     # 2、拿命令的结果,并打印
    18 
    19     # 第一步:先收报头的长度
    20     obj = phone.recv(4)
    21     header_size = struct.unpack('i', obj)[0]
    22 
    23     # 第二步:再收报头
    24     header_bytes = phone.recv(header_size)
    25 
    26     # 第三步:从报头中解析出对真实数据的描述信息
    27     header_json = header_bytes.decode('utf-8')
    28     header_dic = json.loads(header_json)
    29     print(header_dic)
    30     total_size = header_dic['total_size']
    31 
    32     # 第四步: 接收真实的数据
    33     recv_size = 0
    34     recv_data = b''
    35     while recv_size < total_size:
    36         res = phone.recv(1024)  # 1024是一个坑
    37         recv_data += res
    38         recv_size += len(res)
    39     print(recv_data.decode('gbk'))
    40 
    41 phone.close()

    在客户端依次执行,ipconfig 和 dir

    客户端结果为:

     1 >>:ipconfig
     2 {'filename': 'a.txt', 'md5': 'xxdxx', 'total_size': 1481}
     3 
     4 Windows IP 配置
     5 
     6 
     7 无线局域网适配器 本地连接* 3:
     8 
     9    媒体状态  . . . . . . . . . . . . : 媒体已断开连接
    10    连接特定的 DNS 后缀 . . . . . . . : 
    11 
    12 以太网适配器 VMware Network Adapter VMnet1:
    13 
    14    连接特定的 DNS 后缀 . . . . . . . : 
    15    本地链接 IPv6 地址. . . . . . . . : fe80::5d54:4c1:d7d6:c647%6
    16    IPv4 地址 . . . . . . . . . . . . : 192.168.189.1
    17    子网掩码  . . . . . . . . . . . . : 255.255.255.0
    18    默认网关. . . . . . . . . . . . . : 
    19 
    20 以太网适配器 VMware Network Adapter VMnet8:
    21 
    22    连接特定的 DNS 后缀 . . . . . . . : 
    23    本地链接 IPv6 地址. . . . . . . . : fe80::680e:7f79:aed1:fe62%10
    24    IPv4 地址 . . . . . . . . . . . . : 192.168.254.1
    25    子网掩码  . . . . . . . . . . . . : 255.255.255.0
    26    默认网关. . . . . . . . . . . . . : 
    27 
    28 无线局域网适配器 WLAN:
    29 
    30    连接特定的 DNS 后缀 . . . . . . . : DHCP HOST
    31    本地链接 IPv6 地址. . . . . . . . : fe80::9c84:419c:e3af:89dd%11
    32    IPv4 地址 . . . . . . . . . . . . : 192.168.0.106
    33    子网掩码  . . . . . . . . . . . . : 255.255.255.0
    34    默认网关. . . . . . . . . . . . . : 192.168.0.1
    35 
    36 以太网适配器 蓝牙网络连接:
    37 
    38    媒体状态  . . . . . . . . . . . . : 媒体已断开连接
    39    连接特定的 DNS 后缀 . . . . . . . : 
    40 
    41 隧道适配器 Teredo Tunneling Pseudo-Interface:
    42 
    43    连接特定的 DNS 后缀 . . . . . . . : 
    44    IPv6 地址 . . . . . . . . . . . . : 2001:0:9d38:953c:20d3:83ef:d86a:f024
    45    本地链接 IPv6 地址. . . . . . . . : fe80::20d3:83ef:d86a:f024%2
    46    默认网关. . . . . . . . . . . . . : ::
    47 
    48 >>:dir
    49 {'filename': 'a.txt', 'md5': 'xxdxx', 'total_size': 472}
    50  驱动器 C 中的卷是 OS
    51  卷的序列号是 7849-BAF9
    52 
    53  C:Usersxu516PycharmProjectsPython全栈开发第三模块网络编程5 解决粘包问题终极版 的目录
    54 
    55 2018/04/08  23:11    <DIR>          .
    56 2018/04/08  23:11    <DIR>          ..
    57 2018/04/08  22:08               601 struct模块的使用.py
    58 2018/04/08  23:11             1,032 客户端.py
    59 2018/04/08  23:11             1,796 服务端.py
    60                3 个文件          3,429 字节
    61                2 个目录 36,957,728,768 可用字节
    62 
    63 >>:

    代码显示结果正常,没有发生粘包现象,

  • 相关阅读:
    冲刺阶段个人博客9
    冲刺阶段个人博客8
    梦断代码阅读笔记02
    我关于搜狗输入法的用户体验描述
    冲刺阶段个人博客07
    冲刺阶段个人博客06
    冲刺阶段个人博客05
    冲刺阶段个人博客04
    BZOJ 2006 超级钢琴(堆+主席树)
    BZOJ 1924 所驼门王的宝藏(强连通分量缩点+DAG最长链)
  • 原文地址:https://www.cnblogs.com/xudachen/p/8748539.html
Copyright © 2020-2023  润新知