zoukankan      html  css  js  c++  java
  • python网络编程:TCP通讯模板、粘包及解决方案、自定义报头

    本文目录:

    一、TCP通讯模板

    二、远程CMD程序

    三、解决粘包问题

    四、解决粘包问题2

     

    一、TCP通讯模板

    TCP客户端

    import socket
    
    c = socket.socket()
    
    # 连接服务器
    c.connect(("127.0.0.1",65535))
    
    while True:
        # 发送数据
        msg = input(">>>:")
        if not msg:continue
        c.send(msg.encode("utf-8"))
        print("send!")
        # 收数据
        data = c.recv(1024).decode("utf-8")
        print("receiver!")
        print(data)
    
    # 关闭资源
    c.close()

    TCP服务器

    import socket
    # 使用TCP 可以直接默认
    server = socket.socket()
    
    # 指定端口 和 ip     端口 0 - 1023是系统保留的
    server.bind(("127.0.0.1",65535))
    
    # 监听请求  参数为最大半连接数(三次握手未完成的请求  可能是服务器来不及 客户端恶意攻击)
    server.listen(5)
    # 为了可以不断的接受客户端连接请求
    while True:
        # 接受连接请求
        c,addr = server.accept()
        # 为了可以重复收发数据
        while True:
            try:
                # 1024  程序的最大缓冲区容量   返回值类型为bytes类型
                data = c.recv(1024).decode("utf-8")
                # 如果客户端断开连接(客户端调用了close) recv 返回值为空 此时应该结束循环
                if not data:# 在linux中 客户端异常关闭 服务器也会收空
                    print("client closed!")
                    c.close()
                    break
                #解码
                print(data)
                # 回复数据 将原始数据转为大写
                c.send(data.upper().encode("utf-8"))
            except ConnectionResetError:
                print("客户端异常关闭!!")
                c.close()
                break
    # 关闭资源
    server.close()
    
    
    # TCP断开连接的正确姿势
    # 客户端调用close
    # 服务器判断如果接收数据为空则相应的调用close

     

    二、远程CMD程序

    CMD客户端

    import socket
    
    c = socket.socket()
    
    # 连接服务器
    c.connect(("127.0.0.1",65535))
    
    while True:
        # 发送数据
        msg = input(">>>:")
        if not msg:continue
        c.send(msg.encode("utf-8"))
        # while True:
            #     # 收数据
        data = c.recv(1024).decode("gbk")
        print(data)
    
    # 关闭资源
    c.close()
    
    # 问题?  服务器发送的数据超过了接收端缓冲区大小 可直接修改大小来满足服务器传输的大小 但是不长远
    # 上述问题 称之为粘包
    # 思考: 循环每次读取一小部分 直到取完为止
    # 什么时候可以结束循环  前提是让客户端直知道你的数据到底有多长
    # 正确思路:
    """
        发送方
        1.先告诉对方你要发的数据的长度
        2.在发送真实数据
        
        接收方
        1.先接收数据的长度信息
        2.根据长度信息循环获取直到以获取的长度等于总长度
        
    """

    CMD客户端2

    import socket,time
    
    c = socket.socket()
    
    # 连接服务器
    c.connect(("127.0.0.1",65535))
    
    while True:
        # 发送数据
    
        c.send("dir".encode("utf-8"))
        time.sleep(1)
        c.send("dir".encode("utf-8"))
    
        data = c.recv(1024).decode("gbk")
        print(data)
    
    # 关闭资源
    c.close()
    
    # 问题2 当客户端连续两行代码都发送一个dir时  服务器收到了一个dirdir
    # 两个命令黏在一起
    # TCP协议内的一个nagle算法  如果数据量小 并且时间间隔短会将数据合并一个包

    CMD服务器

    #  1.服务器先启动 -> 客户端发送指令 -> 服务器接收后使用subprocess执行命令->将执行结果返回给客户端
    
    import socket,subprocess
    # 使用TCP 可以直接默认
    server = socket.socket()
    
    # 指定端口 和 ip     端口 0 - 1023是系统保留的
    server.bind(("127.0.0.1",65535))
    
    # 监听请求  参数为最大半连接数(三次握手未完成的请求  可能是服务器来不及 客户端恶意攻击)
    server.listen(5)
    # 为了可以不断的接受客户端连接请求
    while True:
        # 接受连接请求
        c,addr = server.accept()
        # 为了可以重复收发数据
        while True:
            try:
                # 1024  程序的最大缓冲区容量   返回值类型为bytes类型
                cmd = c.recv(1024).decode("utf-8")
                # 如果客户端断开连接(客户端调用了close) recv 返回值为kong 此时应该结束循环
                if not cmd:# 在linux中 客户端异常关闭 服务器也会收空
                    print("client closed!")
                    c.close()
                    break
                #解码
                print(cmd)
                # 执行命令
                p = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
                # 将错误信息和正确信息拼接到一起
                res = p.stdout.read() + p.stderr.read()
                print("执行结果长",len(res))
                # 将执行结果发送给客户端
                c.send(res)
            except ConnectionResetError:
                print("客户端异常关闭!!")
                c.close()
                break
    # 关闭资源
    server.close()
    
    
    # TCP断开连接的正确姿势
    # 客户端调用close
    # 服务器判断如果接收数据为空则相应的调用close

     

    三、解决粘包问题

    CMD客户端

    import socket,struct
    
    c = socket.socket()
    
    # 连接服务器
    c.connect(("127.0.0.1",65535))
    
    while True:
        # 发送数据
        msg = input(">>>:")
        if not msg:continue
        c.send(msg.encode("utf-8"))
    
        # 1.先获取长度
        bytes_len = c.recv(4) #对方是i格式 固定4字节
        # 2.转回整型
        total_len = struct.unpack("i",bytes_len)[0]
        # 已经接收的长度
        recv_len = 0
        # 一个表示最终数据的bytes
        finally_data = b''
        # 3.收到的长度小于总长度就继续
        while recv_len < total_len:
            # 循环收数据
            data = c.recv(1024)
            recv_len += len(data)
            finally_data += data
        # 整体解码
        print(finally_data.decode("gbk"))
    
    # 关闭资源
    c.close()
    
    # 问题?  服务器发送的数据超过了接收端缓冲区大小 可直接修改大小来满足服务器传输的大小 但是不长远
    # 上述问题 称之为粘包
    # 思考: 循环每次读取一小部分 直到取完为止
    # 什么时候可以结束循环  前提是让客户端直知道你的数据到底有多长
    # 正确思路:
    """
        发送方
        1.先告诉对方你要发的数据的长度
        2.在发送真实数据
        
        接收方
        1.先接收数据的长度信息
        2.根据长度信息循环获取直到以获取的长度等于总长度
        
        自定义报头未讲
    """

    CMD服务器

    #  1.服务器先启动 -> 客户端发送指令 -> 服务器接收后使用subprocess执行命令->将执行结果返回给客户端
    
    import socket,subprocess,struct
    # 使用TCP 可以直接默认
    server = socket.socket()
    
    # 指定端口 和 ip     端口 0 - 1023是系统保留的
    server.bind(("127.0.0.1",65535))
    
    # 监听请求  参数为最大半连接数(三次握手未完成的请求  可能是服务器来不及 客户端恶意攻击)
    server.listen(5)
    # 为了可以不断的接受客户端连接请求
    while True:
        # 接受连接请求
        c,addr = server.accept()
        # 为了可以重复收发数据
        while True:
            try:
                # 1024  程序的最大缓冲区容量   返回值类型为bytes类型
                cmd = c.recv(1024).decode("utf-8")
                # 如果客户端断开连接(客户端调用了close) recv 返回值为kong 此时应该结束循环
                if not cmd:# 在linux中 客户端异常关闭 服务器也会收空
                    print("client closed!")
                    c.close()
                    break
                #解码
                print(cmd)
                # 执行命令
                p = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
                # 将错误信息和正确信息拼接到一起
                res = p.stdout.read() + p.stderr.read()
                print("执行结果长",len(res))
    
    
                # 1.先发送数据的长度
                data_len = len(res)
                # 长度是一个整型 需要转为字节  1000 b'x001'  2000 b'x001x002'
                # 另外 需要保证 长度信息转换后的结果长度是固定的 否则客户端也会粘包(不知道取多少字节)
                # struct 模块负责将python中的数据类型 转为c语言中结构体
                # 整型转字节
                bytes_len = struct.pack("i",data_len)
                c.send(bytes_len)
                # 2.发送真实数据
                c.send(res)
            except ConnectionResetError:
                print("客户端异常关闭!!")
                c.close()
                break
    # 关闭资源
    server.close()
    
    
    # TCP断开连接的正确姿势
    # 客户端调用close
    # 服务器判断如果接收数据为空则相应的调用close

    #structTest.py文件

    import struct
    
    
    # 整型转字节  i 表示int 长度为4字节   q表示long int 长度为8字节
    print(len(struct.pack("q",10240000000)))
    
    
    # 字节转整型 得到一个元祖
    print(struct.unpack("q",struct.pack("q",10240000000))[0])

     

    四、解决粘包问题2

    CMD客户端

    import socket,struct,json
    
    c = socket.socket()
    
    # 连接服务器
    c.connect(("127.0.0.1",65535))
    
    while True:
        # 发送数据
        msg = input(">>>:")
        if not msg:continue
        c.send(msg.encode("utf-8"))
    
        # 1.先获取报头长度
        bytes_len = c.recv(4) #对方是i格式 固定4字节
        # 2.转回整型
        head_len = struct.unpack("i",bytes_len)[0]
    
        # 3.接受报头数据
        head_bytes = c.recv(head_len)
        # 4.转为json字符串 并转为字典
        head_dic = json.loads(head_bytes.decode("utf-8"))
        print(head_dic)
    
        # 已经接收的长度
        recv_len = 0
        # 一个表示最终数据的bytes
        finally_data = b''
        # 3.收到的长度小于总长度就继续
        while recv_len < head_dic["total_size"]:
            # 循环收数据
            data = c.recv(1024)
            recv_len += len(data)
            finally_data += data
        # 整体解码
        print(finally_data.decode("gbk"))
    
    # 关闭资源
    c.close()
    
    # 问题?  服务器发送的数据超过了接收端缓冲区大小 可直接修改大小来满足服务器传输的大小 但是不长远
    # 上述问题 称之为粘包
    # 思考: 循环每次读取一小部分 直到取完为止
    # 什么时候可以结束循环  前提是让客户端直知道你的数据到底有多长
    # 正确思路:
    """
        发送方
        1.先告诉对方你要发的数据的长度
        2.在发送真实数据
        
        接收方
        1.先接收数据的长度信息
        2.根据长度信息循环获取直到以获取的长度等于总长度
        
        自定义报头未讲
    """

    CMD服务器

    #  1.服务器先启动 -> 客户端发送指令 -> 服务器接收后使用subprocess执行命令->将执行结果返回给客户端
    
    import socket,subprocess,struct,json
    # 使用TCP 可以直接默认
    server = socket.socket()
    
    # 指定端口 和 ip     端口 0 - 1023是系统保留的
    server.bind(("127.0.0.1",65535))
    
    # 监听请求  参数为最大半连接数(三次握手未完成的请求  可能是服务器来不及 客户端恶意攻击)
    server.listen(5)
    # 为了可以不断的接受客户端连接请求
    while True:
        # 接受连接请求
        c,addr = server.accept()
        # 为了可以重复收发数据
        while True:
            try:
                # 1024  程序的最大缓冲区容量   返回值类型为bytes类型
                cmd = c.recv(1024).decode("utf-8")
                # 如果客户端断开连接(客户端调用了close) recv 返回值为kong 此时应该结束循环
                if not cmd:# 在linux中 客户端异常关闭 服务器也会收空
                    print("client closed!")
                    c.close()
                    break
                #解码
                print(cmd)
                # 执行命令
                p = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
                # 将错误信息和正确信息拼接到一起
                res = p.stdout.read() + p.stderr.read()
                print("执行结果长",len(res))
    
                # 1.组装一个报头信息
                head_dic = {
                    "name":"仓老师视频教学 如何做炸鸡!",
                    "md5":"asasasasaas",
                    "total_size":len(res),
                    "type":"video"
                }
                # 2.转json字符串
                head_str = json.dumps(head_dic)
                # 3.转字节
                head_bytes = head_str.encode("utf-8")
                # 4.发送报头长度
                bytes_len = struct.pack("i",len(head_bytes))
                c.send(bytes_len)
                # 5.发送报头
                c.send(head_bytes)
                # 6.发送真实数据
                c.send(res)
    
            except ConnectionResetError:
                print("客户端异常关闭!!")
                c.close()
                break
    # 关闭资源
    server.close()
    
    
    # TCP断开连接的正确姿势
    # 客户端调用close
    # 服务器判断如果接收数据为空则相应的调用close

    # structTest.py文件

    import struct
    
    
    # 整型转字节  i 表示int 长度为4字节   q表示long int 长度为8字节
    print(len(struct.pack("q",10240000000)))
    
    
    # 字节转整型 得到一个元祖
    print(struct.unpack("q",struct.pack("q",10240000000))[0])
  • 相关阅读:
    [转]data类型的Url格式:把小数据直接嵌入到Url中
    SQL 找出某列最小的行记录.
    用 Dos 像数据库一样拎出所有文件.
    Js 正则表达式 RegExp .
    KMP算法C语言实现。弄了好久才搞好。。。
    python如何保证输入键入数字
    数据库关系图:“此数据库没有有效所有者,因此无法安装数据库关系图支持对象&quot;的解决方法
    建立sql数组的一个函数
    实用的240多个jQuery插件
    begin tran,commit tran和rollback tran的用法
  • 原文地址:https://www.cnblogs.com/wuzhengzheng/p/10268527.html
Copyright © 2011-2022 走看看