zoukankan      html  css  js  c++  java
  • 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()
    客户端

        

  • 相关阅读:
    不喜欢数据库编程
    配置 yum 源的两种方法
    编译内核后iptables无法启动问题
    国外免费空间
    iptables--静态防火墙实例教程
    25 Most Frequently Used Linux IPTables Rules Examples
    如何开启或关闭SELinux
    google提供免费企业邮局
    RAID 0, RAID 1, RAID 5, RAID 10 Explained with Diagrams
    CentOS软件管理之fastestmirror和RPMforge
  • 原文地址:https://www.cnblogs.com/louyefeng/p/9580560.html
Copyright © 2011-2022 走看看