执行ECHO命令

问题描述 投票:0回答:2

使用说明

在我正在制作的项目的这个阶段,我需要添加对 ECHO 命令的支持。

ECHO 是一个类似于 PING 的命令,用于测试和调试。它接受单个参数并将其作为 RESP 批量字符串返回。

$ redis-cli PING # The command I implemented in previous stages
PONG
$ redis-cli ECHO hey # The command I will implement in this stage
hey

测试

测试人员将执行这样的程序:

$ ./your_program.sh

然后它会向您的服务器发送带有参数的 ECHO 命令:

$ redis-cli ECHO hey

测试人员期望收到

$3\\r\\nhey\\r\\n
作为响应(这是编码为 RESP 批量字符串的字符串。

这是我的解决方案:

import socket
import threading


def handle_client(conn, addr):
    print(f'Connected to {addr}')
    
    while True:
        data = conn.recv(1024)  # Read data as bytes
        if not data:  # If no data is received, exit the loop
            break
        
        request = data.decode()

        pong = b"+PONG\r\n"

        if request.lower().startswith("echo"):
            # Parse the message for the ECHO command
            parts = request.split("\r\n")
            if len(parts) >= 4:
                res_data = parts[3]  # Extract the actual argument for ECHO (the string after ECHO)
                content_len = len(res_data)  # Get the length of the argument
                # Correctly format the response as a bulk string
                response = f"${content_len}\r\n{res_data}\r\n"
                conn.send(response.encode())  # Send the response back
        else:
            # Default response for PING
            conn.send(b"+PONG\r\n")

    print(f"Connection to {addr} closed")
    conn.close()  # Close the connection with the client

def main():
    print("Logs from your program will appear here!")
    
    # Set up the server socket and start listening for connections
    server_socket = socket.create_server(("localhost", 6379), reuse_port=True)
    server_socket.listen()
    
    while True:
        # Accept a new client connection
        conn, addr = server_socket.accept()
        
        # Create and start a new thread to handle the client
        client_thread = threading.Thread(target=handle_client, args=(conn, addr))
        client_thread.start()

if __name__ == "__main__":
    main()

错误:

Initiating test run...

⚡ This is a turbo test run. https://codecrafters.io/turbo

Running tests. Logs should appear shortly...

[compile] Moved ./.codecrafters/run.sh → ./your_program.sh
[compile] Compilation successful.

[tester::#QQ0] Running tests for Stage #QQ0 (Implement the ECHO command)
[tester::#QQ0] $ ./your_program.sh
[your_program] Logs from your program will appear here!
[tester::#QQ0] $ redis-cli ECHO pineapple
[your_program] Connected to ('127.0.0.1', 39346)
[tester::#QQ0] Expected "pineapple", got "PONG"
[tester::#QQ0] Test failed (try setting 'debug: true' in your codecrafters.yml to see more details)

我认为解析器无法读取 ECHO 命令,但我不知道如何修复它。任何帮助将不胜感激。

python sockets redis tcp echo
2个回答
0
投票

为每个命令定义一个函数,然后在第一个空格字符上分割输入数据,并为该命令调用适当的函数,将剩余的数据传递给该函数。

def pong(data, conn):
    conn.send(b"+PONG\r\n")

def echo(data, conn):
    conn.send(f"${len(data)}\r\n{data}\r\n".encode())

def handle_client(conn, addr):
    print(f'Connected to {addr}')
    
    commands = {
        "PING": pong,
        "ECHO": echo,
    }

    while True:
        data = conn.recv(1024)  # Read data as bytes
        if not data:  # If no data is received, exit the loop
            break
        
        name, _, extra_data = data.decode().rstrip().partition(" ")
        command = commands.get(name.upper(), None)
        if command:
            command(extra_data, conn)

    print(f"Connection to {addr} closed")
    conn.close()  # Close the connection with the client

0
投票

以下是问题的答案:

import threading

def parse_resp(data):
    """Parse RESP format data."""
    data = data.decode()
    if not data:
        return None, None
    
    # Handle array format (*2\r\n$4\r\nECHO\r\n$6\r\norange\r\n)
    if data[0] == '*':
        # Split into lines
        parts = data.split('\r\n')
        # First line contains number of arguments (*2)
        num_args = int(parts[0][1:])
        
        args = []
        i = 1
        for _ in range(num_args):
            # Skip the length indicator ($4)
            str_len = int(parts[i][1:])
            # Get the actual string value
            args.append(parts[i + 1])
            i += 2
            
        return args[0], ' '.join(args[1:]) if len(args) > 1 else ''
    
    return None, None

def pong(data, conn):
    conn.send(b"+PONG\r\n")

def echo(data, conn):
    # Format response in RESP format for bulk strings
    response = f"${len(data)}\r\n{data}\r\n"
    conn.send(response.encode())

def handle_client(conn, addr):
    print(f'Connected to {addr}')
 
    commands = {
        "ECHO": echo,
        "PING": pong,
    }

    while True:
        try:
            data = conn.recv(1024)  # Read data as bytes
            if not data:  # If no data is received, exit the loop
                break
            
            command, args = parse_resp(data)
            if command:
                command_handler = commands.get(command.upper())
                if command_handler:
                    command_handler(args, conn)
        except Exception as e:
            print(f"Error handling client: {e}")
            break

    print(f"Connection to {addr} closed")
    conn.close()

def main():
    print("Logs from your program will appear here!")
    
    server_socket = socket.create_server(("localhost", 6379), reuse_port=True)
    server_socket.listen()
    
    while True:
        conn, addr = server_socket.accept()
        client_thread = threading.Thread(target=handle_client, args=(conn, addr))
        client_thread.start()

if __name__ == "__main__":
    main()
© www.soinside.com 2019 - 2024. All rights reserved.