zoukankan      html  css  js  c++  java
  • Python学习日记(三十一) 黏包问题

    import subprocess
    
    res = subprocess.Popen('dir',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    print('Stdout:',res.stdout.read().decode('gbk'))
    print('Stderr:',res.stderr.read().decode('gbk'))

    PIPE把输出的东西装到一个'水管'里,如果在windows中的编码格式是gbk,执行结果:

    Stdout:  驱动器 C 中的卷是 系统
     卷的序列号是 85C0-669A
    
     C:UsersAdministratorPycharmProjectsInternet_program 的目录
    
    2019/09/16  13:48    <DIR>          .
    2019/09/16  13:48    <DIR>          ..
    2019/09/16  13:47    <DIR>          .idea
    2019/09/16  13:46                21 Client1.py
    2019/09/16  13:42                 0 Client2.py
    2019/09/16  13:48               207 Sever1.py
    2019/09/16  01:41                70 time_test.py
    2019/09/14  23:51    <DIR>          venv
                   4 个文件            298 字节
                   4 个目录 45,863,636,992 可用字节
    
    Stderr: 

    在这里也可以使用os.popen()但是它会不管正确和错误的结果都放在一起,而用subprocess能够分别拿到正确和错误的信息

    基于TCP实现的黏包

    Sever:

    import socket
    sk = socket.socket()
    sk.bind(('127.0.0.1',8092))
    sk.listen()
    conn,addr = sk.accept()
    while True:
        cmd = input('<<<')
        conn.send(cmd.encode('gbk'))
        ret = conn.recv(1024).decode('gbk')
        print(ret)
    conn.close()
    sk.close()

    Client:

    import socket
    import subprocess
    sk = socket.socket()
    sk.connect(('127.0.0.1',8092))
    while True:
        cmd = sk.recv(1024).decode('gbk')
        ret = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
        std_out = 'stdout:' + (ret.stdout.read()).decode('gbk')
        std_err = 'stderr:' + (ret.stderr.read()).decode('gbk')
        print(std_out)
        print(std_err)
        sk.send(std_out.encode('gbk'))
        sk.send(std_err.encode('gbk'))
    sk.close()

    执行结果:

    Sever:

    <<<dir;ls
    stdout: 驱动器 C 中的卷是 系统
     卷的序列号是 85C0-669A
    
     C:UsersAdministratorPycharmProjectsInternet_program 的目录
    
    
    <<<ipconfig
    stderr:找不到文件
    
    <<<

    Client:

    stdout: 驱动器 C 中的卷是 系统
     卷的序列号是 85C0-669A
    
     C:UsersAdministratorPycharmProjectsInternet_program 的目录
    
    
    stderr:找不到文件
    
    stdout:
    Windows IP 配置
    
    
    以太网适配器 Bluetooth 网络连接 2:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    以太网适配器 本地连接:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    无线局域网适配器 无线网络连接:
    
       连接特定的 DNS 后缀 . . . . . . . : 
       本地链接 IPv6 地址. . . . . . . . : fe80::8c6:36a9:6fa6:8018%14
       IPv4 地址 . . . . . . . . . . . . : 192.168.43.216
       子网掩码  . . . . . . . . . . . . : 255.255.255.0
       默认网关. . . . . . . . . . . . . : 192.168.43.1
    
    隧道适配器 本地连接* 3:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    stderr:

    当我们在sever端输入dir;ls命令时,只有stdout的结果跑出来,而当我们输入ipconfig这个命令时,系统将上一次dir;ls未执行完的stderr的结果给跑出来。像这样没有接受完全或者接受多了的就是黏包现象。

    TCP会有黏包现象但是它不丢包。

    基于UDP实现的黏包

    Sever:

    import socket
    sk = socket.socket(type=socket.SOCK_DGRAM)
    sk.bind(('127.0.0.1',8092))
    msg,addr = sk.recvfrom(10240)
    
    while 1:
        cmd = input('<<<')
        if cmd == 'q':
            break
        sk.sendto(cmd.encode('gbk'),addr)
        msg,addr = sk.recvfrom(10240)
        print(msg.decode('gbk'))
    
    sk.close()

    Client:

    import socket
    import subprocess
    sk = socket.socket(type=socket.SOCK_DGRAM)
    addr = ('127.0.0.1',8092)
    sk.sendto('Start'.encode('utf-8'),addr)
    while 1:
        cmd,addr = sk.recvfrom(10240)
        ret = subprocess.Popen(cmd.decode('gbk'),shell=True,stderr=subprocess.PIPE,stdout=subprocess.PIPE)
        std_out = 'Stdout:' + (ret.stdout.read()).decode('gbk')
        std_err = 'Stderr:' + (ret.stderr.read()).decode('gbk')
        print(std_out)
        print(std_err)
        sk.sendto(std_out.encode('gbk'),addr)
        sk.sendto(std_err.encode('gbk'),addr)
    sk.close()

    执行结果:

    Sever:

    <<<dir;ls
    Stdout: 驱动器 C 中的卷是 系统
     卷的序列号是 85C0-669A
    
     C:UsersAdministratorPycharmProjectsInternet_program 的目录
    
    
    <<<dir
    Stderr:找不到文件
    
    <<<ipconfig
    Stdout: 驱动器 C 中的卷是 系统
     卷的序列号是 85C0-669A
    
     C:UsersAdministratorPycharmProjectsInternet_program 的目录
    
    2019/09/16  14:43    <DIR>          .
    2019/09/16  14:43    <DIR>          ..
    2019/09/16  14:37    <DIR>          .idea
    2019/09/16  14:43               553 Client1.py
    2019/09/16  13:42                 0 Client2.py
    2019/09/16  14:43               306 Sever1.py
    2019/09/16  01:41                70 time_test.py
    2019/09/14  23:51    <DIR>          venv
                   4 个文件            929 字节
                   4 个目录 45,855,449,088 可用字节
    
    <<<pwd
    Stderr:
    <<<ip
    Stdout:
    Windows IP 配置
    
    
    以太网适配器 Bluetooth 网络连接 2:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    以太网适配器 本地连接:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    无线局域网适配器 无线网络连接:
    
       连接特定的 DNS 后缀 . . . . . . . : 
       本地链接 IPv6 地址. . . . . . . . : fe80::8c6:36a9:6fa6:8018%14
       IPv4 地址 . . . . . . . . . . . . : 192.168.43.216
       子网掩码  . . . . . . . . . . . . : 255.255.255.0
       默认网关. . . . . . . . . . . . . : 192.168.43.1
    
    隧道适配器 本地连接* 3:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    <<<

    Client:

    Stdout: 驱动器 C 中的卷是 系统
     卷的序列号是 85C0-669A
    
     C:UsersAdministratorPycharmProjectsInternet_program 的目录
    
    
    Stderr:找不到文件
    
    Stdout: 驱动器 C 中的卷是 系统
     卷的序列号是 85C0-669A
    
     C:UsersAdministratorPycharmProjectsInternet_program 的目录
    
    2019/09/16  14:43    <DIR>          .
    2019/09/16  14:43    <DIR>          ..
    2019/09/16  14:37    <DIR>          .idea
    2019/09/16  14:43               553 Client1.py
    2019/09/16  13:42                 0 Client2.py
    2019/09/16  14:43               306 Sever1.py
    2019/09/16  01:41                70 time_test.py
    2019/09/14  23:51    <DIR>          venv
                   4 个文件            929 字节
                   4 个目录 45,855,449,088 可用字节
    
    Stderr:
    Stdout:
    Windows IP 配置
    
    
    以太网适配器 Bluetooth 网络连接 2:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    以太网适配器 本地连接:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    无线局域网适配器 无线网络连接:
    
       连接特定的 DNS 后缀 . . . . . . . : 
       本地链接 IPv6 地址. . . . . . . . : fe80::8c6:36a9:6fa6:8018%14
       IPv4 地址 . . . . . . . . . . . . : 192.168.43.216
       子网掩码  . . . . . . . . . . . . : 255.255.255.0
       默认网关. . . . . . . . . . . . . : 192.168.43.1
    
    隧道适配器 本地连接* 3:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    Stderr:
    Stdout:
    Stderr:'pwd' 不是内部或外部命令,也不是可运行的程序
    或批处理文件。
    
    Stdout:
    Stderr:'ip' 不是内部或外部命令,也不是可运行的程序
    或批处理文件。

    可以看出UDP不会有黏包现象,会产生丢包现象,没发完就不发了,不完整也不可靠。

    黏包成因

    TCP协议的数据传送

    拆包机制

    当发送端缓冲区的长度大于网卡的MTU时,TCP会将这次发送的数据拆成几个数据包发送出去。MTU是Maximum Transmission Unit的缩写,意思是网络上传送最大数据包,MTU是字节单位,大部分网络设备的MTU都是1500.如果本机的MTU比网关的MTU大,大的数据包就会被拆开来传送,这样会产生很多数据包碎片,增加丢包率,降低网络速度。

    在正常情况下它的拆包可理解为:

    面向流的通信特点和Nagle算法

    TCP(transport control protocol,传输控制协议),是面向连接的,面向流的,提供高可靠性的服务。收发两端(客户端和服务端)都要有一一成对的socket,因此发送端为了将多个发往接收端的包,更有效地发往对方,使用了优化算法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。这样接收端就难于分辨出来了,必须提供科学的拆包机制。即面向流的通信是无消息保护边界的。

    对于空消息:TCP是基于数据流的,于是收发消息不能为空,这就需要在客户端和服务端都添加空消息的处理机制,防止程序卡住,而UDP协议是基于数据报的,即便是你输入的是空内容(直接回车),也可以被发送,UDP协议会帮你封装上消息然后发出去。

    可靠黏包的TCP协议:TCP协议数据不会丢,没有收完包,就会下次接收,会继续上次继续接受。

    基于tcp协议特点的黏包现象成因

    当我们在socket服务端发送值1、2,然后根据优化算法,它会把1先放到这个缓存当中等一等,然后再把2一起封装起来,然后再发出去,因此我们看到的就是黏包现象

    这种现象的表面现象是两个send太近且发送的消息太短

    发送端可以使1K1K地发送数据,而接收端的应用程序可以两K两K地提走数据,当然也有可能一次提走3K或6K数据,或者一次只提走几个字节的数据。也就是说,应用程序所看到的数据是一个整体,或者说是一个流(stream),一条消息有多少字节对应程序是不可见的,因此TCP协议是面向流的协议,这也是容易出现黏包问题的原因。而UDP协议是面向消息的协议,每个UDP段都是一条消息,应用程序必须以消息单位提取数据,不能一次提取任意字节的数据,这一点和TCP是很不同的。

    解决黏包的方法

    解决方案一:

    Sever:

    import socket
    sk = socket.socket()
    sk.bind(('127.0.0.1',8080))
    sk.listen()
    conn,addr = sk.accept()
    
    while True:
        cmd = input('<<<')
        if cmd == 'q':
            conn.send(b'q')
            break
        conn.send(cmd.encode('gbk'))
        num = conn.recv(1024).decode('utf-8')
        conn.send(b'ok')
        res = conn.recv(int(num)).decode('gbk')
        print(res)
    
    conn.close()
    sk.close()

    Client:

    import socket
    import subprocess
    
    sk = socket.socket()
    sk.connect(('127.0.0.1',8080))
    while True:
        cmd = sk.recv(1024).decode('gbk')
        if cmd == 'q':
            break
        res = subprocess.Popen(cmd,shell=True,
                               stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE)
        std_out = res.stdout.read()
        std_err = res.stderr.read()
        sk.send(str(len(std_out) + len(std_err)).encode('utf-8'))
        sk.recv(1024)
        print('Stdout:' + std_out.decode('gbk'))
        print('Stderr:' + std_err.decode('gbk'))
        sk.send(std_out)
        sk.send(std_err)
    
    sk.close()

    执行结果:

    Sever:

    <<<dir
     驱动器 C 中的卷是 系统
     卷的序列号是 85C0-669A
    
     C:UsersAdministratorPycharmProjectsInternet_program 的目录
    
    2019/09/17  15:33    <DIR>          .
    2019/09/17  15:33    <DIR>          ..
    2019/09/17  15:31    <DIR>          .idea
    2019/09/17  15:33               623 Client1.py
    2019/09/16  13:42                 0 Client2.py
    2019/09/17  15:21               389 Sever1.py
    2019/09/16  01:41                70 time_test.py
    2019/09/14  23:51    <DIR>          venv
                   4 个文件          1,082 字节
                   4 个目录 45,031,833,600 可用字节
    
    <<<ls
    'ls' 不是内部或外部命令,也不是可运行的程序
    或批处理文件。
    
    <<<ipconfig
    
    Windows IP 配置
    
    
    以太网适配器 Bluetooth 网络连接 2:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    以太网适配器 本地连接:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    无线局域网适配器 无线网络连接:
    
       连接特定的 DNS 后缀 . . . . . . . : 
       本地链接 IPv6 地址. . . . . . . . : fe80::8c6:36a9:6fa6:8018%14
       IPv4 地址 . . . . . . . . . . . . : 192.168.43.216
       子网掩码  . . . . . . . . . . . . : 255.255.255.0
       默认网关. . . . . . . . . . . . . : 192.168.43.1
    
    隧道适配器 本地连接* 3:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    <<<

    Client:

    Stdout: 驱动器 C 中的卷是 系统
     卷的序列号是 85C0-669A
    
     C:UsersAdministratorPycharmProjectsInternet_program 的目录
    
    2019/09/17  15:33    <DIR>          .
    2019/09/17  15:33    <DIR>          ..
    2019/09/17  15:31    <DIR>          .idea
    2019/09/17  15:33               623 Client1.py
    2019/09/16  13:42                 0 Client2.py
    2019/09/17  15:21               389 Sever1.py
    2019/09/16  01:41                70 time_test.py
    2019/09/14  23:51    <DIR>          venv
                   4 个文件          1,082 字节
                   4 个目录 45,031,833,600 可用字节
    
    Stderr:
    Stdout:
    Stderr:'ls' 不是内部或外部命令,也不是可运行的程序
    或批处理文件。
    
    Stdout:
    Windows IP 配置
    
    
    以太网适配器 Bluetooth 网络连接 2:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    以太网适配器 本地连接:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    无线局域网适配器 无线网络连接:
    
       连接特定的 DNS 后缀 . . . . . . . : 
       本地链接 IPv6 地址. . . . . . . . : fe80::8c6:36a9:6fa6:8018%14
       IPv4 地址 . . . . . . . . . . . . : 192.168.43.216
       子网掩码  . . . . . . . . . . . . : 255.255.255.0
       默认网关. . . . . . . . . . . . . : 192.168.43.1
    
    隧道适配器 本地连接* 3:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    Stderr:

    这种写法的好处就是能确定Sever到底要接受多少数据,不好的地方就是多了一次交互

    解决方案二:使用struct模块

    用struct模块我们能把一个数据类型转换成固定长度的bytes

    这里以数字类型举例,'i'代表int类型:

    import struct
    print(struct.pack('i',2048),len(struct.pack('i',2048)))         #b'x00x08x00x00'    4
    print(struct.pack('i',204800),len(struct.pack('i',204800)))     #b'x00 x03x00'       4
    print(struct.pack('i',2048000),len(struct.pack('i',2048000)))   #b'x00@x1fx00'       4

    当后面的数值戳过一定范围的时候程序就会报错

    Sever:

    import socket
    import struct
    sk = socket.socket()
    sk.bind(('127.0.0.1',8080))
    sk.listen()
    conn,addr = sk.accept()
    
    while True:
        cmd = input('<<<')
        if cmd == 'q':
            conn.send(b'q')
            break
        conn.send(cmd.encode('gbk'))
        num = conn.recv(4)
        num = struct.unpack('i',num)[0]
        res = conn.recv(int(num)).decode('gbk')
        print(res)
    
    conn.close()
    sk.close()

    Client:

    import socket
    import subprocess
    import struct
    
    sk = socket.socket()
    sk.connect(('127.0.0.1',8080))
    while True:
        cmd = sk.recv(1024).decode('gbk')
        if cmd == 'q':
            break
        res = subprocess.Popen(cmd,shell=True,
                               stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE)
        std_out = res.stdout.read()
        std_err = res.stderr.read()
        len_num = len(std_out) + len(std_err)
        num_by = struct.pack('i',len_num)
        print('Stdout:' + std_out.decode('gbk'))
        print('Stderr:' + std_err.decode('gbk'))
        sk.send(num_by)
        sk.send(std_out)
        sk.send(std_err)
    
    sk.close()

    执行结果:

    <<<dir
     驱动器 C 中的卷是 系统
     卷的序列号是 85C0-669A
    
     C:UsersAdministratorPycharmProjectsInternet_program 的目录
    
    2019/09/17  16:25    <DIR>          .
    2019/09/17  16:25    <DIR>          ..
    2019/09/17  16:23    <DIR>          .idea
    2019/09/17  16:25               659 Client1.py
    2019/09/16  13:42                 0 Client2.py
    2019/09/17  16:22               400 Sever1.py
    2019/09/17  16:08               288 time_test.py
    2019/09/14  23:51    <DIR>          venv
                   4 个文件          1,347 字节
                   4 个目录 45,025,951,744 可用字节
    
    <<<configip
    'configip' 不是内部或外部命令,也不是可运行的程序
    或批处理文件。
    
    <<<ipconfig
    
    Windows IP 配置
    
    
    以太网适配器 Bluetooth 网络连接 2:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    以太网适配器 本地连接:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    无线局域网适配器 无线网络连接:
    
       连接特定的 DNS 后缀 . . . . . . . : 
       本地链接 IPv6 地址. . . . . . . . : fe80::8c6:36a9:6fa6:8018%14
       IPv4 地址 . . . . . . . . . . . . : 192.168.43.216
       子网掩码  . . . . . . . . . . . . : 255.255.255.0
       默认网关. . . . . . . . . . . . . : 192.168.43.1
    
    隧道适配器 本地连接* 3:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    <<<
    Sever执行结果
    Stdout: 驱动器 C 中的卷是 系统
     卷的序列号是 85C0-669A
    
     C:UsersAdministratorPycharmProjectsInternet_program 的目录
    
    2019/09/17  16:25    <DIR>          .
    2019/09/17  16:25    <DIR>          ..
    2019/09/17  16:23    <DIR>          .idea
    2019/09/17  16:25               659 Client1.py
    2019/09/16  13:42                 0 Client2.py
    2019/09/17  16:22               400 Sever1.py
    2019/09/17  16:08               288 time_test.py
    2019/09/14  23:51    <DIR>          venv
                   4 个文件          1,347 字节
                   4 个目录 45,025,951,744 可用字节
    
    Stderr:
    Stdout:
    Stderr:'configip' 不是内部或外部命令,也不是可运行的程序
    或批处理文件。
    
    Stdout:
    Windows IP 配置
    
    
    以太网适配器 Bluetooth 网络连接 2:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    以太网适配器 本地连接:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    无线局域网适配器 无线网络连接:
    
       连接特定的 DNS 后缀 . . . . . . . : 
       本地链接 IPv6 地址. . . . . . . . : fe80::8c6:36a9:6fa6:8018%14
       IPv4 地址 . . . . . . . . . . . . : 192.168.43.216
       子网掩码  . . . . . . . . . . . . : 255.255.255.0
       默认网关. . . . . . . . . . . . . : 192.168.43.1
    
    隧道适配器 本地连接* 3:
    
       媒体状态  . . . . . . . . . . . . : 媒体已断开
       连接特定的 DNS 后缀 . . . . . . . : 
    
    Stderr:
    Client执行结果

    实现一个大文件的传输和下载

    当我们在网络上传输所有数据时,这些数据都叫数据包,数据包里的所有数据都叫报文,报文里不止有你的数据还有IP地址、MAC地址、端口号等,所有的报文都有报头,这是由协议规定的。所有在网络上传播数据包的协议里都有一个报头。什么时候需要自己定制报文?比如说复杂的应用上就会应用到、传输文件的时候(文件名、文件大小、文件类型、存储路径等)...

    其实在网络传输的过程当中处处有协议,协议就是一堆报头和报文(都由字节组成)。

    Sever:

    import socket
    import struct
    import json
    buffer = 1024
    sk = socket.socket()
    sk.bind(('127.0.0.1',8080))
    sk.listen()
    
    conn,addr = sk.accept()
    
    head_len = conn.recv(4)
    struct.unpack('i',head_len)[0]
    json_head = conn.recv(head_len).decode('utf-8')
    head = json.loads(json_head)
    file_size = head['fileSize']
    
    with open(r'dir\%s'%head['fileName'],'wb') as f:
        while file_size:
            if file_size >= buffer:
                content = conn.recv(buffer)
                f.write(content)
                file_size -= buffer
            else:
                content = conn.recv(buffer)
                f.write(content)
                break
    conn.close()
    sk.close()

    Client:

    import socket
    import struct
    import os
    import json
    
    sk = socket.socket()
    sk.connect(('127.0.0.1',8080))
    buffer = 1024
    head = {'filePath' : r'C:UsersAdministratorDesktop专题海報資料夾专题海报',
            'fileName' : r'专题海报',
            'fileSize' : None}
    file_path = os.path.join(head['filePath'],head['fileName'])
    file_size = os.path.getsize(file_path)
    
    head['fileSize'] = file_size
    json_head = json.dumps(head)                            #字典转成字典
    bytes_head = json_head.encode('utf-8')                  #字符串转bytes
    
    head_len = len(bytes_head)                              #报头的长度
    pack_len = struct.pack('i',head_len)
    
    sk.send(pack_len)                                       #先发报头的长度
    sk.send(bytes_head)                                     #再发bytes类型的报头
    with open(r'dir\%s'%file_path,'rb') as f:
            while file_size:
                    if file_size >= buffer:
                            content = f.read(buffer)  # 每次文件读出的内容
                            sk.send(content)
                            file_size -= buffer
                    else:
                            content = f.read(file_size)
                            sk.send(content)
                            break
    sk.close()
  • 相关阅读:
    圣诞树
    删除临时表并且插入数据
    sql语句中查询用in的时候,按in的顺序来输出
    xmlhelper and excelhelper
    几个小知识点。
    根据页面上记录数和页面大小获取总页数
    SQL语句的疑问
    katie melua the closest thing to crazy
    something about table
    little things
  • 原文地址:https://www.cnblogs.com/Fantac/p/11527758.html
Copyright © 2011-2022 走看看