• Python套接字


    一.基于tcp的套接字

      tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接服务端

      tcp服务端

    from socket import *
    
    # 服务端必须满足至少三点:
    # 1.绑定一个固定的ip和port
    # 2.一直对外提供服务,稳定运行
    # 3.能够支持并发
    server = socket(AF_INET, SOCK_STREAM)
    server.bind(('127.0.0.1', 9555))
    server.listen(5)
    
    client, addr = server.accept()
    data = client.recv(1024)
    print(data.decode('utf-8'))
    client.send(data.upper())
    
    client.close()
    server.close()

      tcp客户端

    from socket import *
    client = socket(AF_INET,SOCK_STREAM)
    client.connect(('127.0.0.1',9555))
    
    msg = input('>>>:').strip()
    client.send(msg.encode('utf-8'))
    data = client.recv(1024)
    print(data)
    
    client.close()

    二.修改bug+通信循环+链接循环

      上述存在客户端退出时服务端即会崩溃的bug,而且无法实现用户的多次输入,以及服务端无法一直对外服务的问题,对此进行修改

      服务端

    from socket import *
    
    server = socket(AF_INET, SOCK_STREAM)
    server.bind(('127.0.0.1', 8081))
    server.listen(5)
    
    # 链接循环
    while True:
        conn, client_addr = server.accept()
        print(client_addr)
    
        # 通信循环
        while True:
            try:
                data = conn.recv(1024)
                if len(data) == 0: break  # 针对linux系统
                print('-->收到客户端的消息: ', data)
                conn.send(data.upper())
            except ConnectionResetError:
                break
    
        conn.close()
    
    server.close()

      客户端

    from socket import *
    
    client = socket(AF_INET, SOCK_STREAM)
    client.connect(('127.0.0.1', 8081))
    
    # 通信循环
    while True:
        msg=input('>>: ').strip() #msg=''
        if len(msg) == 0:continue
        client.send(msg.encode('utf-8')) #client.send(b'')
        # print('has send')
        data=client.recv(1024)
        # print('has recv')
        print(data)
    
    client.close()

    三.模拟ssh实现远程执行命令

    from socket import *
    import subprocess
    
    server = socket(AF_INET, SOCK_STREAM)
    server.bind(('127.0.0.1', 8081))
    server.listen(5)
    
    # 链接循环
    while True:
        conn, client_addr = server.accept()
        print(client_addr)
    
        # 通信循环
        while True:
            try:
                cmd = conn.recv(1024) #cmd=b'dir'
                if len(cmd) == 0: break  # 针对linux系统
                obj=subprocess.Popen(cmd.decode('utf-8'),
                                 shell=True,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE
                                 )
                stdout=obj.stdout.read()
                stderr=obj.stderr.read()
                print(len(stdout) + len(stderr))
                conn.send(stdout+stderr)
            except ConnectionResetError:
                break
    
        conn.close()
    
    server.close()
    服务端
    from socket import *
    
    client = socket(AF_INET, SOCK_STREAM)
    client.connect(('127.0.0.1', 8081))
    
    # 通信循环
    while True:
        cmd=input('>>: ').strip()
        if len(cmd) == 0:continue
        client.send(cmd.encode('utf-8'))
        cmd_res=client.recv(1024000)
        print(cmd_res.decode('gbk'))
    
    client.close()
    客户端

    四.粘包问题以及解决方法

      粘包问题:

        只有TCP有粘包现象,UDP不存在粘包,粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的.

      简单粘包问题案例

    from socket import *
    import subprocess
    
    server = socket(AF_INET, SOCK_STREAM)
    server.bind(('127.0.0.1', 8081))
    server.listen(5)
    
    conn,_=server.accept()
    data1=conn.recv(5)
    print('第一次收: ',data1)
    
    data2=conn.recv(5)
    print('第二次收: ',data2)
    
    data3=conn.recv(4)
    print('第三次收: ',data3)
    
    # 粘包问题是tcp协议流式传输数据的方式导致的
    # 如何解决粘包问题:接收端能够精确地收干净每个数据包没有任何残留
    服务端
    from socket import *
    
    client = socket(AF_INET, SOCK_STREAM)
    client.connect(('127.0.0.1', 8081))
    
    # tcp协议会将数据量较小且发送时间间隔较短的数据合并成一个数据报发送
    client.send(b'hello')
    client.send(b'world')
    client.send(b'egon')
    客户端

    五.解决粘包问题

    from socket import *
    import subprocess
    import struct
    import json
    
    server = socket(AF_INET, SOCK_STREAM)
    server.bind(('127.0.0.1', 8081))
    server.listen(5)
    
    # 链接循环
    while True:
        conn, client_addr = server.accept()
        print(client_addr)
    
        # 通信循环
        while True:
            try:
                cmd = conn.recv(1024)  # cmd=b'dir'
                if len(cmd) == 0: break  # 针对linux系统
                obj = subprocess.Popen(cmd.decode('utf-8'),
                                       shell=True,
                                       stdout=subprocess.PIPE,
                                       stderr=subprocess.PIPE
                                       )
                stdout = obj.stdout.read()
                stderr = obj.stderr.read()
                # 1. 先制作报头
                header_dic = {
                    'filename': 'a.txt',
                    'md5': 'asdfasdf123123x1',
                    'total_size': len(stdout) + len(stderr)
                }
                header_json = json.dumps(header_dic)
                header_bytes = header_json.encode('utf-8')
    
                # 2. 先发送4个bytes(包含报头的长度)
                conn.send(struct.pack('i', len(header_bytes)))
                # 3  再发送报头
                conn.send(header_bytes)
    
                # 4. 最后发送真实的数据
                conn.send(stdout)
                conn.send(stderr)
            except ConnectionResetError:
                break
    
        conn.close()
    
    server.close()
    服务端
    from socket import *
    import struct
    import json
    
    client = socket(AF_INET, SOCK_STREAM)
    client.connect(('127.0.0.1', 8081))
    
    # 通信循环
    while True:
        cmd = input('>>: ').strip()
        if len(cmd) == 0: continue
        client.send(cmd.encode('utf-8'))
        # 1. 先收4bytes,解出报头的长度
        header_size = struct.unpack('i', client.recv(4))[0]
    
        # 2. 再接收报头,拿到header_dic
        header_bytes = client.recv(header_size)
        header_json = header_bytes.decode('utf-8')
        header_dic = json.loads(header_json)
        print(header_dic)
        total_size = header_dic['total_size']
    
        # 3. 接收真正的数据
        cmd_res = b''
        recv_size = 0
        while recv_size < total_size:
            data = client.recv(1024)
            recv_size += len(data)
            cmd_res += data
    
        print(cmd_res.decode('gbk'))
    
    client.close()
    客户端

        

  • 相关阅读:
    js 构造函数 constructor
    js foreach和map区别
    js 静态方法和实例方法
    学习知识点总结(es6篇)
    java1.5新特性(转)
    21 Managing the Activity Lifecycle
    Java进阶Collection集合框架概要·16
    Java进阶核心之集合框架Map下集·18
    Java进阶核心之集合框架Set·19
    Java进阶核心之集合框架List·17
  • 原文地址:https://www.cnblogs.com/louyefeng/p/9580560.html
Copyright © 2020-2023  润新知