• Python中Socket编程(TCP、UDP)


    1. TCP协议下的如何解决粘包问题

      TCP(transport control protocol 传输控制协议)  使用Nagle算法,将多次间隔较小且数据量小的数据,合并成大的数据块;接受端无法识别每条数据的边界,因此产生粘包现象。

    """
    Server
    """
    from socket import *
    
    back_log = 5
    bufsize = 1024
    ip_port = ('127.0.0.1', 8080)
    
    tcp_server = socket(AF_INET, SOCK_STREAM)  # 数据流
    tcp_server.bind(ip_port)
    tcp_server.listen(back_log)
    
    while True:
        print('服务端开始处理连接。。。')
        conn, addr = tcp_server.accept()
        print('客户端连接', conn)
        print('客户端地址', addr)
        while True:
            try:
                data = conn.recv(bufsize)
                if not data:
                    break
                print('接收到的数据', data)
                conn.send(data.upper())
            except Exception as e:
                print(e)
                break
    """
    Client
    """
    from socket import *
    
    bufsize = 1024
    ip_port = ('127.0.0.1', 8080)
    
    tcp_client = socket(AF_INET, SOCK_STREAM)
    tcp_client.connect(ip_port)
    tcp_client.send('hello'.encode('utf-8'))
    tcp_client.send('world'.encode('utf-8'))
    response = tcp_client.recv(bufsize)
    print('response is ==> ', response)  # response is ==>  b'HELLOWORLD'

    解决思路:告知接收端数据长度,导入struct模块,将字节长度封装成4个字节发送给接收方;

    服务端 =====》TCP实现远程操作命令

    from socket import *
    import subprocess,struct
    
    bufsize = 1024
    back_log = 5
    ip_port = ('127.0.0.1', 8080)
    
    tcp_server = socket(AF_INET, SOCK_STREAM)
    tcp_server.bind(ip_port)
    tcp_server.listen(back_log)
    while True:
        conn, addr = tcp_server.accept()
        print('current connection', conn)
        while True:
            try:
                cmd = conn.recv(bufsize)
                if not cmd:
                    break
                print('data from client', cmd)
    
                res = subprocess.Popen(cmd.decode('utf-8'), shell=True,
                                       stderr=subprocess.PIPE,
                                       stdin=subprocess.PIPE,
                                       stdout=subprocess.PIPE)
                cmd_res = res.stderr.read()
                if not cmd_res:
                    cmd_res = res.stdout.read()
                print('response is:', cmd_res)
    
                data_length = struct.pack('i', len(cmd_res))
                conn.send(data_length)
                conn.send(cmd_res)
            except Exception as e:
                print(e)
                break
        # conn.close()

    客户端 ====》

    from socket import *
    import struct
    
    bufsize = 100
    ip_port = ('127.0.0.1', 8080)
    tcp_client = socket(AF_INET, SOCK_STREAM)
    tcp_client.connect(ip_port)
    
    while True:
        cmd = input('>>>> ').strip()
        if not cmd:
            continue
        if cmd == 'quit':
            break
        tcp_client.send(cmd.encode('utf-8'))
    
        length_data = tcp_client.recv(4)
    
        length = struct.unpack('i', length_data)[0]
        print(length)
        response = b''
        recsize = 0
        while recsize < length:
            response += tcp_client.recv(bufsize)
            recsize = len(response)
            # print('execute result is:', response)  # 接受字节长度小于发送数据长度,产生粘包
        print('execute result is:', response.decode('gbk'))
    tcp_client.close()

    2. TCP协议如何实现多个客户端连接(并发处理)

    导入socketserver模块,实现ocketserver.BaseRequestHandler,重写 handle 方法

    使用

    ThreadingTCPServer,线程实现并发
    import socketserver
    
    
    class MyServer(socketserver.BaseRequestHandler):
        def handle(self):
            print('conn is', self.request)  # conn
            print('addr is', self.client_address)  # addr
    
            while True:
                try:
                    data = self.request.recv(1024)
                    if not data:
                        break
                    self.request.sendall(data.upper())
                except Exception as e:
                    print(e)
                    break
    
    
    if __name__ == '__main__':
        ip_port = ('127.0.0.1', 8080)
        s = socketserver.ThreadingTCPServer(ip_port, MyServer)
        s.serve_forever()


    3. 基于UDP套接字

      UDP 与TCP 不同,使用socket时用的时 SOCK_DGRAM 数据报

      sendto()发送的是元组数据类型,包含数据以及连接

      recvfrom()接收的也是数据以及连接

    服务端 ====》

    from socket import *
    
    ip_port = ('127.0.0.1', 8080)
    buf_size = 1024
    
    udp_server = socket(AF_INET, SOCK_DGRAM)  # datagram 数据报
    udp_server.bind(ip_port)
    
    while True:
        data, addr = udp_server.recvfrom(buf_size)
        print(data)
        udp_server.sendto(data.upper(), addr)

    客户端====》

    from socket import *
    
    ip_port = ('127.0.0.1', 8080)
    buf_size = 1024
    
    udp_client = socket(AF_INET, SOCK_DGRAM)  # datagram 数据报
    
    while True:
        msg = input('==>: ').strip()
        udp_client.sendto(msg.encode('utf-8'), ip_port)
        response, addr = udp_client.recvfrom(buf_size)
        print(response.decode('utf-8'))
  • 相关阅读:
    如何让研发团队保持敏捷并不断进步?
    敏捷方法适合什么样的团队?
    规模化敏捷中的“三要”和“三不要”
    敏捷开发中如何使用看板方法创造价值
    4.0 初步预计更新内容
    3.0 环境应用(待更新)
    5.0 Genymotion安装以及基础使用
    2.0 python+appium环境搭建
    1.0 python-client以及ui自动化介绍
    教你一招另辟蹊径抓取美团火锅数据
  • 原文地址:https://www.cnblogs.com/louiszh/p/12391742.html
Copyright © 2020-2023  润新知