zoukankan      html  css  js  c++  java
  • 二十六、socket(套接字),struck模块用法,TCP粘包问题

    一、socket通信

    1.客户端
    import socket
    
    client = socket.socket()  # 拿电话
    client.connect(('127.0.0.1', 8080))  # 拨号   写的是对方的ip和port
    
    client.send(b'hello world!')  # 对别人说话
    data = client.recv(1024)  # 听别人说话
    print(data)
    
    client.close()  # 挂电话
    2.服务端
    import socket
    
    server = socket.socket()  # 买手机 不传参数默认用的就是TCP协议
    server.bind(('127.0.0.1', 8080))  # bind((host,port))  插电话卡  绑定ip和端口
    server.listen(5)  # 开机    半连接池
    
    conn, addr = server.accept()  # 接听电话  等着别人给你打电话     阻塞
    data = conn.recv(1024)  # 听别人说话 接收1024个字节数据          阻塞
    print(data)
    conn.send(b'hello baby~')  # 给别人回话
    
    conn.close()  # 挂电话
    server.close()  # 关机

    二、连接循环+通讯循环

    1.客户端
    import socket
    
    client = socket.socket()  # 拿到电话
    client.connect(("127.0.0.1", 8080))  # 拨号  里面是访问的ip和端口
    while True:
        msg = input("客户端说:").encode("utf8")
        if len(msg) == 0: continue
        client.send(msg)
        if msg.decode("utf8") == "bye":
            break
        data = client.recv(1024)  # 听别人讲
        print(data.decode("utf-8"))
    client.close()
    2.服务端
    import socket
    
    server = socket.socket()  # 买个手机,不传参数就是默认TCP协议
    server.bind(("127.0.0.1", 8080))  # 绑定ip地址和8080端口
    server.listen(5)  # 开机 半连接池(可以接收五个等待传输客户端)
    while True:
        # conn 是传输的数据 addr:客户端传输过来的ip和端口
        conn, addr = server.accept()  # 接通通讯,等待别人传输数据
    
        data = conn.recv(1024).decode("utf8")  # 接收数据,且最大能接收1024字节
        print(data)
        if data == "bye":
            conn.close()  # 挂机电话
            server.close()
            break
        msg = input("服务器说:").encode("utf8")
        conn.send(msg)
    
    # conn.close()  # 挂机电话
    # server.close()  # 关闭服务器

    三、TCP粘包问题

    同时执行多条命令之后,得到的结果很可能只有一部分,在执行其他命令的时候又接收到之前执行的另外一部分结果,这种显现就是黏包。

    粘包:

      1.传输过程中发送过快,内容比较小,会粘在一起

    1.客户端
    import socket
    
    
    client = socket.socket()  # 拿电话
    client.connect(('127.0.0.1',8080))  # 拨号   写的是对方的ip和port
    
    client.send(b'hello')
    client.send(b'world')
    client.send(b'baby')
    
    2.服务端
    import socket
    
    server = socket.socket()  # 买手机 不传参数默认用的就是TCP协议
    server.bind(('127.0.0.1', 8080))  # bind((host,port))  插电话卡  绑定ip和端口
    server.listen(5)  # 开机    半连接池
    
    conn, addr = server.accept()  # 接听电话  等着别人给你打电话     阻塞
    data = conn.recv(1024)  # 听别人说话 接收1024个字节数据          阻塞
    print(data)
    data = conn.recv(1024)  # 听别人说话 接收1024个字节数据          阻塞
    print(data)
    data = conn.recv(1024)  # 听别人说话 接收1024个字节数据          阻塞
    print(data)
    
    #三次接收可能一次就接收完

    四、struck模块

    import struct
    
    # res = 'akdjsladlkjafkldjfgsdafhjksdfhfdgfdsgdfgssgdglkjdfsfdsadkfjlksdjf;klsdkl;fk;lsfdgklj;sfkldgj;kldfg;lfkd;lgk;lsdkfg;lkfd;glskljdklsajkldsa'
    # print('最原始的', len(res))
    # res1 = len(res)
    # print(res1)  # 137
    # res2 = struct.pack("i", len(res))
    # print(len(res2))  # 4
    # res3 = struct.unpack("i", res2)[0]
    # print(res3)  # 解包之后137
    
    # 当原始数据特别大的时候 i模式打包不了 需要更换模式?
    # 如果遇到数据量特别大的情况 该如何解决?
    d = {
        'name': 'jason',
        'file_size': 3455435435345354524534532456546546565466564366463654543453454353455,
        'info': '为大家的骄傲'
    }
    import json
    
    json_d = json.dumps(d)
    print(len(json_d))
    
    res1 = struct.pack('i', len(json_d))
    print(len(res1))
    
    res2 = struct.unpack('i', res1)[0]
    print('解包之后的', res2)

    五、解决粘包问题

    1.客户端
    import socket
    import struct
    import json
    
    client = socket.socket()
    client.connect(('127.0.0.1', 8080))
    
    while True:
        msg = input('>>>:').encode('utf-8')
        if len(msg) == 0: continue
        client.send(msg)
        # 1.先接受字典报头
        header_dict = client.recv(4)
        # 2.解析报头 获取字典的长度
        dict_size = struct.unpack('i', header_dict)[0]  # 解包的时候一定要加上索引0
        # 3.接收字典数据  ,字符串转成二进制中长度就等于字节大小
        dict_bytes = client.recv(dict_size)
        dict_json = json.loads(dict_bytes.decode('utf-8'))
        # 4.从字典中获取信息
        print(dict_json)
        recv_size = 0
        real_data = b''
        while recv_size < dict_json.get('file_size'):  # real_size = 102400
            data = client.recv(1024)
            real_data += data
            recv_size += len(data)
        print(real_data.decode('gbk'))
    
    2.服务端
    import socket
    import subprocess
    import struct
    import json
    
    server = socket.socket()
    server.bind(('127.0.0.1', 8080))
    server.listen(5)
    
    while True:
        conn, addr = server.accept()
        while True:
            try:
                cmd = conn.recv(1024)
                if len(cmd) == 0: break
                cmd = cmd.decode('utf-8')
                obj = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                res = obj.stdout.read() + obj.stderr.read()
                d = {'name': 'jason', 'file_size': len(res), 'info': 'asdhjkshasdad'}
                json_d = json.dumps(d)
                # 1.先制作一个字典的报头
                header = struct.pack('i', len(json_d))
                # 2.发送字典报头
                conn.send(header)
                # 3.发送字典
                conn.send(json_d.encode('utf-8'))
                # 4.再发真实数据
                conn.send(res)
                # conn.send(obj.stdout.read())
                # conn.send(obj.stderr.read())
            except ConnectionResetError:
                break
        conn.close()
  • 相关阅读:
    升级到macos sierra xcode8 requires additional components to support runing and debugging choose Install to add required components
    读书笔记
    Tableview 优化Cell的复用机制01
    奇闻趣事
    媒体平台
    iOS真机调试问题-App installation failed,The maximum number of apps for free development profiles has been reached.
    (null): Linker command failed with exit code 1 (use -v to see invocation)
    @import
    iOS开发-xcdatamodeld文件 CoreData的介绍和使用,sqlite的使用
    WPF TreeGrid Binding 简易实现方式
  • 原文地址:https://www.cnblogs.com/wukai66/p/11317689.html
Copyright © 2011-2022 走看看