zoukankan      html  css  js  c++  java
  • python学习----9.3---基于tcp通信协议的套接字(通信循环,链接循环)、粘包

    服务端必须满足至少三点:

      1.绑定一个固定的ip和port

      2.一直对外提供服务,稳定运行

      3.能够支持并发

    通信循环

    from socket import *
    
    server = socket(AF_INET, SOCK_STREAM)
    server.bind(('127.0.0.1', 8080))
    server.listen(5)
    
    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', 8080))
    
    # 通信循环
    while True:
        msg=input('>>: ').strip()
        client.send(msg.encode('utf-8'))
        data=client.recv(1024)
        print(data)
    
    client.close()
    客户端

    链接循环

    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()
        if len(msg)==0:continue
        client.send(msg.encode(('utf-8')))
        data=client.recv(1024)
        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)
                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'))
        data=client.recv(1024000)
        print(data.decode('gbk'))
    
    client.close()
    客户端

    Struct模块

      该模块可以把一个类型,如数字转换成bytes类型

    import struct
    
    # obj1=struct.pack('i',13321111111)
    # print(obj1,len(obj1))
    
    # res1=struct.unpack('i',obj1)
    # print(res1[0])
    
    obj1=struct.pack('q',1332111111111)
    print(obj1,len(obj1))
    View Code

    模拟ssh实现远程执行命令(解决粘包问题终极版)

    from socket import *
    import struct
    import json
    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)
                if len(cmd) == 0: break
                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': 'sadsdadsasd12312321',
                    '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 json
    import struct
    
    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()
    客户端

    两种情况下会发生粘包现象

      1、发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据了很小,会合到一起,产生粘包)

    #_*_coding:utf-8_*_
    __author__ = 'Linhaifeng'
    from socket import *
    ip_port=('127.0.0.1',8080)
    
    tcp_socket_server=socket(AF_INET,SOCK_STREAM)
    tcp_socket_server.bind(ip_port)
    tcp_socket_server.listen(5)
    
    
    conn,addr=tcp_socket_server.accept()
    
    
    data1=conn.recv(10)
    data2=conn.recv(10)
    
    print('----->',data1.decode('utf-8'))
    print('----->',data2.decode('utf-8'))
    
    conn.close()
    服务端
    #_*_coding:utf-8_*_
    __author__ = 'Linhaifeng'
    import socket
    BUFSIZE=1024
    ip_port=('127.0.0.1',8080)
    
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    res=s.connect_ex(ip_port)
    
    
    s.send('hello'.encode('utf-8'))
    s.send('feng'.encode('utf-8'))
    客户端

      2、接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包) 

    #_*_coding:utf-8_*_
    __author__ = 'Linhaifeng'
    from socket import *
    ip_port=('127.0.0.1',8080)
    
    tcp_socket_server=socket(AF_INET,SOCK_STREAM)
    tcp_socket_server.bind(ip_port)
    tcp_socket_server.listen(5)
    
    
    conn,addr=tcp_socket_server.accept()
    
    
    data1=conn.recv(2) #一次没有收完整
    data2=conn.recv(10)#下次收的时候,会先取旧的数据,然后取新的
    
    print('----->',data1.decode('utf-8'))
    print('----->',data2.decode('utf-8'))
    
    conn.close()
    服务端
    #_*_coding:utf-8_*_
    __author__ = 'Linhaifeng'
    import socket
    BUFSIZE=1024
    ip_port=('127.0.0.1',8080)
    
    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    res=s.connect_ex(ip_port)
    
    
    s.send('hello feng'.encode('utf-8'))
    客户端
  • 相关阅读:
    【xinsir】githook之precommit分享
    node进程一些信号的意义
    ES6篇
    Webpack4篇
    Node篇
    Vuex篇
    WebStorage篇
    HTML5篇
    html5语义化标签大全
    emmet语法
  • 原文地址:https://www.cnblogs.com/Liu-guang-hui/p/9580257.html
Copyright © 2011-2022 走看看