zoukankan      html  css  js  c++  java
  • 16 [网络编程]-粘包

    1、粘包

     粘包,就是指两次结果粘到一起了。它的发生主要是因为socket缓冲区导致的,来看一下

     

    你的程序实际上无权直接操作网卡的,你操作网卡都是通过操作系统给用户程序暴露出来的接口,
    那每次你的程序要给远程发数据时,其实是先把数据从用户态copy到内核态,
    这样的操作是耗资源和时间的,频繁的在内核态和用户态之前交换数据势必会导致发送效率降低,
     因此socket 为提高传输效率,发送方往往要收集到足够多的数据后才发送一次数据给对方。
    若连续几次需要send的数据都很少,
    通常TCP socket 会根据优化算法把这些数据合成一个TCP段后一次发送出去,
    这样接收方就收到了粘包数据。
    

      

    2、粘包问题只存在于TCP中,Not UDP

    •  TCP协议是面向流的协议
    还是看上图,发送端可以是一K一K地发送数据,
    而接收端的应用程序可以两K两K地提走数据,当然也有可能一次提走3K或6K数据,或者一次只提走几个字节的数据,
    也就是说,应用程序所看到的数据是一个整体,或说是一个流(stream),一条消息有多少字节对应用程序是不可见的,
    因此TCP协议是面向流的协议,这也是容易出现粘包问题的原因
    
    • UDP是面向消息的协议
    UDP是面向消息的协议,每个UDP段都是一条消息,应用程序必须以消息为单位提取数据,不能一次提取任意字节的数据,
    这一点和TCP是很不同的。怎样定义消息呢?可以认为对方一次性write/send的数据为一个消息,需要明白的是当对方send一条信息的时候,
    无论底层怎样分段分片,TCP协议层会把构成整条消息的数据段排序完成后才呈现在内核缓冲区。
    

      

    总结

    1. TCP(transport control protocol,传输控制协议)是面向连接的,面向流的,提供高可靠性服务。收发两端(客户端和服务器端)都要有一一成对的socket,因此,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。这样,接收端,就难于分辨出来了,必须提供科学的拆包机制。 即面向流的通信是无消息保护边界的。
    2. UDP(user datagram protocol,用户数据报协议)是无连接的,面向消息的,提供高效率服务。不会使用块的合并优化算法,, 由于UDP支持的是一对多的模式,所以接收端的skbuff(套接字缓冲区)采用了链式结构来记录每一个到达的UDP包,在每个UDP包中就有了消息头(消息来源地址,端口等信息),这样,对于接收端来说,就容易进行区分处理了。 即面向消息的通信是有消息保护边界的。
    3. tcp是基于数据流的,于是收发的消息不能为空,这就需要在客户端和服务端都添加空消息的处理机制,防止程序卡住,而udp是基于数据报的,即便是你输入的是空内容(直接回车),那也不是空消息,udp协议会帮你封装上消息头,实验略

    3、send与recv的区别

     

    4、粘包现象

    • 两次send:数据量小,时间间隔很短,会发生粘包

      (1)服务端

    # 两次send:数据量小,时间间隔很短,会发生粘包
    
    import socket
    import time
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind(('127.0.0.1', 9999))
    server.listen(5)
    
    print('... waiting...')
    conn, addr = server.accept()
    
    #data1 = conn.recv(1024)
    
    data1 = conn.recv(1)  # 当只取一个字符的时候,剩下的数据还在缓存池里面,下次会继续取出来
    print('第一次', data1)
    
    data2 = conn.recv(1024)
    print('第二次', data2)
    
    conn.close()
    server.close()

      

      (2)客户端

    # 两次send:数据量小,时间间隔很短,会发生粘包
    
    import socket
    import time
    
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client.connect(('127.0.0.1', 9999))
    
    client.send('hello'.encode('utf-8'))
    
    # time.sleep(1)  两次send直接隔一段时间,不会发生粘包现象
    
    client.send('world'.encode('utf-8'))
    
    client.close()

      

    5、解决粘包问题:普通版

    问题的根源在于,接收端不知道发送端将要传送的字节流的长度,所以解决粘包的方法就是围绕,如何让发送端在发送数据前,把自己将要发送的字节流总大小让接收端知晓,

    然后接收端来一个死循环接收完所有数据

     (1)服务端

    import socket
    import subprocess
    
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    server.bind(('127.0.0.1', 9994))
    
    server.listen(5)
    
    while True:
        print('waiting...')
        conn, addr = server.accept()
    
        while True:
            try:
                data = conn.recv(1024)
                print('=》', data)
                if not data:
                    break
    
                obj = subprocess.Popen(data.decode('utf-8'), shell=True,
                                       stdout=subprocess.PIPE,
                                       stderr=subprocess.PIPE,
                                       )
    
                # 3.把取出命令的结果
                stdout = obj.stdout.read()
                stderr = obj.stderr.read()
    
                # 3.1 把数据的长度发送给客户端
                total_size = len(stdout+stderr)
                conn.send(str(total_size).encode('utf-8'))
    
                # 3.2 在发送真实的数据
                conn.send(stdout)   # 粘包可以
                conn.send(stderr)
    
            except ConnectionResetError:
                break
    
        conn.close()
    
    
    server.close()

      

      (2)客户端

    import socket
    
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    client.connect(('127.0.0.1', 9994))
    
    while True:
    
        data = input('>>>').strip()         # 粘包现象,当输入ipconfig的时候,缓存池会存放太多的结果
        if not data:
            continue
        client.send(data.encode('utf-8'))
    
        # 2.接受数据的长度
        total_size = client.recv(1024)
    
        # 3.取出报文的长度
        total_size = int(total_size.decode('utf-8'))
    
        # 3.一段段的取数据
        total_data = b''
        recv_size = 0
    
        while recv_size < total_size:  # 接受的数据长度 = len(total_data) 已经取完了,就退出
            data = client.recv(1024)
            total_data += data
            recv_size += len(data)
    
        print(total_data.decode('gbk'))
    
    client.close()
    C:Python34python.exe C:/PycharmProjects/Luffy_project/Luffy-网络编程/07-解决粘包问题/03-客户端.py
    >>>dir
     驱动器 C 中的卷没有标签。
     卷的序列号是 E08A-FCF5
    
     C:PycharmProjectsLuffy_projectLuffy-网络编程7-解决粘包问题 的目录
    
    2018/03/28 周三  下午 08:27    <DIR>          .
    2018/03/28 周三  下午 08:27    <DIR>          ..
    2018/03/28 周三  下午 08:10             1,114 02-服务端2.py
    2018/03/28 周三  下午 08:27               818 03-客户端.py
                   2 个文件          1,932 字节
                   2 个目录 124,168,138,752 可用字节
    
    >>>
    >>>ipconfig
    
    Windows IP 配置
    
    
    无线局域网适配器 无线网络连接 5:
    
       连接特定的 DNS 后缀 . . . . . . . : 
       本地链接 IPv6 地址. . . . . . . . : fe80::7512:dae3:9ef5:f6d3%19
       IPv4 地址 . . . . . . . . . . . . : 192.168.191.1
       子网掩码  . . . . . . . . . . . . : 255.255.255.0
       默认网关. . . . . . . . . . . . . : 
    
    无线局域网适配器 无线网络连接:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    以太网适配器 本地连接:
    
       连接特定的 DNS 后缀 . . . . . . . : 
       IPv6 地址 . . . . . . . . . . . . : 2001:da8:4015:a:2060:b9c5:9ddb:1343
       临时 IPv6 地址. . . . . . . . . . : 2001:da8:4015:a:65c2:fdc:ae01:f622
       本地链接 IPv6 地址. . . . . . . . : fe80::2060:b9c5:9ddb:1343%12
       IPv4 地址 . . . . . . . . . . . . : 10.8.6.11
       子网掩码  . . . . . . . . . . . . : 255.255.254.0
       默认网关. . . . . . . . . . . . . : fe80::3ee5:a6ff:fe6c:98c1%12
                                           10.8.7.254
    
    以太网适配器 VMware Network Adapter VMnet1:
    
       连接特定的 DNS 后缀 . . . . . . . : 
       本地链接 IPv6 地址. . . . . . . . : fe80::91c:c41:5755:bd67%14
       IPv4 地址 . . . . . . . . . . . . : 192.168.48.1
       子网掩码  . . . . . . . . . . . . : 255.255.255.0
       默认网关. . . . . . . . . . . . . : 
    
    以太网适配器 VMware Network Adapter VMnet8:
    
       连接特定的 DNS 后缀 . . . . . . . : 
       本地链接 IPv6 地址. . . . . . . . : fe80::4cfa:7057:d006:cbf0%15
       IPv4 地址 . . . . . . . . . . . . : 192.168.28.1
       子网掩码  . . . . . . . . . . . . : 255.255.255.0
       默认网关. . . . . . . . . . . . . : 
    
    隧道适配器 isatap.{D0793028-C9C4-44BD-84A9-7ACFE0D6D454}:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    隧道适配器 本地连接*:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    隧道适配器 isatap.{592418B3-F47A-489C-A9E5-1EDEC7B499C1}:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    隧道适配器 isatap.{D8C47ABB-48E9-4B35-BE81-29A998780E04}:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    隧道适配器 isatap.{F30B37DD-15CE-4B19-8B0F-BF1495C3081D}:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    隧道适配器 isatap.{1A8AE88C-5BF7-4219-B60F-72E3ACF6FF35}:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    隧道适配器 6TO4 Adapter:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    >>>
    >>>dir
     驱动器 C 中的卷没有标签。
     卷的序列号是 E08A-FCF5
    
     C:PycharmProjectsLuffy_projectLuffy-网络编程7-解决粘包问题 的目录
    
    2018/03/28 周三  下午 08:27    <DIR>          .
    2018/03/28 周三  下午 08:27    <DIR>          ..
    2018/03/28 周三  下午 08:10             1,114 02-服务端2.py
    2018/03/28 周三  下午 08:27               818 03-客户端.py
                   2 个文件          1,932 字节
                   2 个目录 124,168,138,752 可用字节
    
    >>>
    运行结果

    6、解决粘包问题:struct模块

    • 为字节流加上自定义固定长度报头也可以借助于第三方模块struc
    import struct
    
    # 为字节流加上自定义固定长度报头 4个 bytes
    data = 'alex123'
    ret = struct.pack('i', len(data))    # i 模式
    print(ret,ret.decode('utf-8'), len(ret), type(ret)) # b'x07x00x00x00'     4 <class 'bytes'>
    
    
    obj = struct.unpack('i', ret)
    print(obj)   # (10,)
    data_len = obj[0]
    print(data_len)     # 数据长度 7 个

     

      (1)服务端

    import socket
    import struct
    import subprocess
    
    
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    server.bind(('127.0.0.1', 9994))
    
    server.listen(5)
    
    while True:
        print('waiting...')
        conn, addr = server.accept()
    
        while True:
            try:
                data = conn.recv(1024)
                print('=》', data)
                if not data:
                    break
    
                obj = subprocess.Popen(data.decode('utf-8'), shell=True,
                                       stdout=subprocess.PIPE,
                                       stderr=subprocess.PIPE,
                                       )
    
                # 3.把取出命令的结果
                stdout = obj.stdout.read()
                stderr = obj.stderr.read()
    
                # 3.1 把数据的长度发送给客户端
                # 第一步:制作固定长度的报头
                total_size = len(stdout + stderr)
                ret = struct.pack('i',total_size)  # bytes格式
    
                # 第二部:把报头发送给客户端
                conn.send(ret)
    
                # 第三部:发送真实数据
                conn.send(stdout)   # 粘包可以
                conn.send(stderr)
    
            except ConnectionResetError:
                break
    
        conn.close()
    
    
    server.close()

      

      (2)客户端

    import socket
    import struct
    
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    client.connect(('127.0.0.1', 9994))
    
    while True:
    
        data = input('>>>').strip()         # 粘包现象,当输入ipconfig的时候,缓存池会存放太多的结果
        if not data:
            continue
        client.send(data.encode('utf-8'))
    
        # 2.接受报头
        ret = client.recv(1024)
    
        # 3.从报头中解析出对真实数据的描述信息(数据的长度)
        obj = struct.unpack('i',ret)
        total_size = obj[0]
    
        # 3.一段段的取数据
        total_data = b''
        recv_size = 0
    
        while recv_size < total_size:  # 接受的数据长度 = len(total_data) 已经取完了,就退出
            data = client.recv(1024)
            total_data += data
            recv_size += len(data)
    
        print(total_data.decode('gbk'))
    
    client.close()
    C:Python34python.exe C:/PycharmProjects/Luffy_project/Luffy-网络编程/08-粘包-struct模块/03-客户端.py
    >>>ipconfig
    
    Windows IP 配置
    
    
    无线局域网适配器 无线网络连接 5:
    
       连接特定的 DNS 后缀 . . . . . . . : 
       本地链接 IPv6 地址. . . . . . . . : fe80::7512:dae3:9ef5:f6d3%19
       IPv4 地址 . . . . . . . . . . . . : 192.168.191.1
       子网掩码  . . . . . . . . . . . . : 255.255.255.0
       默认网关. . . . . . . . . . . . . : 
    
    无线局域网适配器 无线网络连接:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    以太网适配器 本地连接:
    
       连接特定的 DNS 后缀 . . . . . . . : 
       IPv6 地址 . . . . . . . . . . . . : 2001:da8:4015:a:2060:b9c5:9ddb:1343
       临时 IPv6 地址. . . . . . . . . . : 2001:da8:4015:a:65c2:fdc:ae01:f622
       本地链接 IPv6 地址. . . . . . . . : fe80::2060:b9c5:9ddb:1343%12
       IPv4 地址 . . . . . . . . . . . . : 10.8.6.11
       子网掩码  . . . . . . . . . . . . : 255.255.254.0
       默认网关. . . . . . . . . . . . . : fe80::3ee5:a6ff:fe6c:98c1%12
                                           10.8.7.254
    
    以太网适配器 VMware Network Adapter VMnet1:
    
       连接特定的 DNS 后缀 . . . . . . . : 
       本地链接 IPv6 地址. . . . . . . . : fe80::91c:c41:5755:bd67%14
       IPv4 地址 . . . . . . . . . . . . : 192.168.48.1
       子网掩码  . . . . . . . . . . . . : 255.255.255.0
       默认网关. . . . . . . . . . . . . : 
    
    以太网适配器 VMware Network Adapter VMnet8:
    
       连接特定的 DNS 后缀 . . . . . . . : 
       本地链接 IPv6 地址. . . . . . . . : fe80::4cfa:7057:d006:cbf0%15
       IPv4 地址 . . . . . . . . . . . . : 192.168.28.1
       子网掩码  . . . . . . . . . . . . : 255.255.255.0
       默认网关. . . . . . . . . . . . . : 
    
    隧道适配器 isatap.{D0793028-C9C4-44BD-84A9-7ACFE0D6D454}:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    隧道适配器 本地连接*:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    隧道适配器 isatap.{592418B3-F47A-489C-A9E5-1EDEC7B499C1}:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    隧道适配器 isatap.{D8C47ABB-48E9-4B35-BE81-29A998780E04}:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    隧道适配器 isatap.{F30B37DD-15CE-4B19-8B0F-BF1495C3081D}:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    隧道适配器 isatap.{1A8AE88C-5BF7-4219-B60F-72E3ACF6FF35}:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    隧道适配器 6TO4 Adapter:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    >>>dir
     驱动器 C 中的卷没有标签。
     卷的序列号是 E08A-FCF5
    
     C:PycharmProjectsLuffy_projectLuffy-网络编程8-粘包-struct模块 的目录
    
    2018/03/28 周三  下午 10:30    <DIR>          .
    2018/03/28 周三  下午 10:30    <DIR>          ..
    2018/03/28 周三  下午 09:09               360 01-struct.py
    2018/03/28 周三  下午 09:10             1,281 02-服务端2.py
    2018/03/28 周三  下午 09:13               877 03-客户端.py
    2018/03/28 周三  下午 09:15               436 04-struct超出.py
    2018/03/28 周三  下午 09:39               902 05-标准数据报头格式.py
    2018/03/28 周三  下午 10:30             1,738 06-服务端2.py
    2018/03/28 周三  下午 10:30             1,222 07-客户端.py
                   7 个文件          6,816 字节
                   2 个目录 124,167,741,440 可用字节
    
    >>>
    运行结果

    7、数据长度超出struct的标准

    8、制作标准报头

    9、解决粘包问题:json struct

    import json,struct
    #假设通过客户端上传1T:1073741824000的文件a.txt
    
    #为避免粘包,必须自定制报头
    header={'file_size':1073741824000,'file_name':'/a/b/c/d/e/a.txt','md5':'8f6fbf8347faa4924a76856701edb0f3'} #1T数据,文件路径和md5值
    
    #为了该报头能传送,需要序列化并且转为bytes
    head_bytes=bytes(json.dumps(header),encoding='utf-8') #序列化并转成bytes,用于传输
    
    #为了让客户端知道报头的长度,用struck将报头长度这个数字转成固定长度:4个字节
    head_len_bytes=struct.pack('i',len(head_bytes)) #这4个字节里只包含了一个数字,该数字是报头的长度
    
    #客户端开始发送
    conn.send(head_len_bytes) #先发报头的长度,4个bytes
    conn.send(head_bytes) #再发报头的字节格式
    conn.sendall(文件内容) #然后发真实内容的字节格式
    
    #服务端开始接收
    head_len_bytes=s.recv(4) #先收报头4个bytes,得到报头长度的字节格式
    x=struct.unpack('i',head_len_bytes)[0] #提取报头的长度
    
    head_bytes=s.recv(x) #按照报头长度x,收取报头的bytes格式
    header=json.loads(json.dumps(header)) #提取报头
    
    #最后根据报头的内容提取真实的数据,比如
    real_data_len=s.recv(header['file_size'])
    s.recv(real_data_len)
    

      

      (1)服务端

    import socket
    import struct
    import subprocess
    import json
    
    
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    server.bind(('127.0.0.1', 9994))
    
    server.listen(5)
    
    while True:
        print('waiting...')
        conn, addr = server.accept()
    
        while True:
            try:
                data = conn.recv(1024)
                print('=》', data)
                if not data:
                    break
    
                obj = subprocess.Popen(data.decode('utf-8'), shell=True,
                                       stdout=subprocess.PIPE,
                                       stderr=subprocess.PIPE,
                                       )
    
                # 3.把取出命令的结果
                stdout = obj.stdout.read()
                stderr = obj.stderr.read()
    
                # 3.1 把数据的长度发送给客户端
                # 第一步:制作报头
                total_size = len(stdout + stderr)
                header_dict = {
                    'filename': 'a.txt',
                    'md5': 'afdsafsaf',
                    'total_size': total_size
                }
                header_json = json.dumps(header_dict)  # 报头的json样式
                header_bytes = header_json.encode('utf-8')          # 报头---报头.json---报头.bytes
    
                # 发送报头的长度
                header_len = struct.pack('i', len(header_bytes))    # 报头bytes---> len()---> struct
                conn.send(header_len)
    
                # 第二部:把报头发送给客户端
                conn.send(header_bytes)
    
                # 第三部:发送真实数据
                conn.send(stdout)   # 粘包可以
                conn.send(stderr)
    
            except ConnectionResetError:
                break
    
        conn.close()
    
    
    server.close()

      (2)客户端

    import socket
    import struct
    import json
    
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    client.connect(('127.0.0.1', 9994))
    
    while True:
    
        data = input('>>>').strip()         # 粘包现象,当输入ipconfig的时候,缓存池会存放太多的结果
        if not data:
            continue
        client.send(data.encode('utf-8'))
    
        # 2.接受报头的长度         4 个bytes----》struct----》 header_bytes的len
        header_bytes_len = client.recv(1024)
        header_bytes_len = struct.unpack('i', header_bytes_len)[0]
    
        # 接收报头的json数据
        header_bytes = client.recv(header_bytes_len)
        print(header_bytes)
    
        # 3.从报头中解析出对真实数据的描述信息(数据的长度)
        header_json = header_bytes.decode('utf-8')
        header_dict = json.loads(header_json)
    
        total_size = header_dict['total_size']
    
        # 3.一段段的取数据
        total_data = b''
        recv_size = 0
    
        while recv_size < total_size:  # 接受的数据长度 = len(total_data) 已经取完了,就退出
            data = client.recv(1024)
            total_data += data
            recv_size += len(data)
    
        print(total_data.decode('gbk'))
    
    client.close()
    C:Python34python.exe C:/PycharmProjects/Luffy_project/Luffy-网络编程/08-粘包-struct模块/07-客户端.py
    >>>ipconfig
    b'{"total_size": 2587, "md5": "afdsafsaf", "filename": "a.txt"}'
    
    Windows IP 配置
    
    
    无线局域网适配器 无线网络连接 5:
    
       连接特定的 DNS 后缀 . . . . . . . : 
       本地链接 IPv6 地址. . . . . . . . : fe80::7512:dae3:9ef5:f6d3%19
       IPv4 地址 . . . . . . . . . . . . : 192.168.191.1
       子网掩码  . . . . . . . . . . . . : 255.255.255.0
       默认网关. . . . . . . . . . . . . : 
    
    无线局域网适配器 无线网络连接:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    以太网适配器 本地连接:
    
       连接特定的 DNS 后缀 . . . . . . . : 
       IPv6 地址 . . . . . . . . . . . . : 2001:da8:4015:a:2060:b9c5:9ddb:1343
       临时 IPv6 地址. . . . . . . . . . : 2001:da8:4015:a:65c2:fdc:ae01:f622
       本地链接 IPv6 地址. . . . . . . . : fe80::2060:b9c5:9ddb:1343%12
       IPv4 地址 . . . . . . . . . . . . : 10.8.6.11
       子网掩码  . . . . . . . . . . . . : 255.255.254.0
       默认网关. . . . . . . . . . . . . : fe80::3ee5:a6ff:fe6c:98c1%12
                                           10.8.7.254
    
    以太网适配器 VMware Network Adapter VMnet1:
    
       连接特定的 DNS 后缀 . . . . . . . : 
       本地链接 IPv6 地址. . . . . . . . : fe80::91c:c41:5755:bd67%14
       IPv4 地址 . . . . . . . . . . . . : 192.168.48.1
       子网掩码  . . . . . . . . . . . . : 255.255.255.0
       默认网关. . . . . . . . . . . . . : 
    
    以太网适配器 VMware Network Adapter VMnet8:
    
       连接特定的 DNS 后缀 . . . . . . . : 
       本地链接 IPv6 地址. . . . . . . . : fe80::4cfa:7057:d006:cbf0%15
       IPv4 地址 . . . . . . . . . . . . : 192.168.28.1
       子网掩码  . . . . . . . . . . . . : 255.255.255.0
       默认网关. . . . . . . . . . . . . : 
    
    隧道适配器 isatap.{D0793028-C9C4-44BD-84A9-7ACFE0D6D454}:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    隧道适配器 本地连接*:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    隧道适配器 isatap.{592418B3-F47A-489C-A9E5-1EDEC7B499C1}:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    隧道适配器 isatap.{D8C47ABB-48E9-4B35-BE81-29A998780E04}:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    隧道适配器 isatap.{F30B37DD-15CE-4B19-8B0F-BF1495C3081D}:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    隧道适配器 isatap.{1A8AE88C-5BF7-4219-B60F-72E3ACF6FF35}:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    隧道适配器 6TO4 Adapter:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    >>>dir
    b'{"total_size": 763, "md5": "afdsafsaf", "filename": "a.txt"}'
     驱动器 C 中的卷没有标签。
     卷的序列号是 E08A-FCF5
    
     C:PycharmProjectsLuffy_projectLuffy-网络编程8-粘包-struct模块 的目录
    
    2018/03/30 周五  下午 11:52    <DIR>          .
    2018/03/30 周五  下午 11:52    <DIR>          ..
    2018/03/28 周三  下午 09:09               360 01-struct.py
    2018/03/28 周三  下午 09:10             1,281 02-服务端2.py
    2018/03/28 周三  下午 09:13               877 03-客户端.py
    2018/03/30 周五  下午 11:52               436 04-struct超出.py
    2018/03/28 周三  下午 09:39               902 05-标准数据报头格式.py
    2018/03/28 周三  下午 10:30             1,738 06-服务端2.py
    2018/03/28 周三  下午 10:30             1,222 07-客户端.py
                   7 个文件          6,816 字节
                   2 个目录 124,165,222,400 可用字节
    
    >>>
    运行结果

    10

  • 相关阅读:
    jquery表格伸展
    jquery单选框 复选框表格高亮 选中
    jquery表单验证
    jquery下拉框实现将左边的选项添加到右边区域
    jquery checkbox选中状态
    关于.net页面提交后css样式不生效的发现
    asp.net页面后退,重复弹出上一页对话框处理办法
    这几天做完简易酒店管理系统,对Sql Server执行计划的浅显了解
    温故而知新--sql存储过程复习
    网站前端性能优化之javascript和css
  • 原文地址:https://www.cnblogs.com/venicid/p/8679306.html
Copyright © 2011-2022 走看看