取不存在的键

👁️ 2 人浏览 💬 0 人评论 ❤️ 添加收藏

roundtrip GET z(没存过),交回什么?

贯穿全条的内存版 TCP(判题机不联网;接口和真 socket 一样,真机上换成 socket.socket() 就是真的):net = Net()lis = listen(net, 端口) 开监听;cli = connect(net, 端口) 客户端连上(交回客户端这头,服务端那头进 accept 队列);srv = lis.accept() 领一条连接;sendall 把字节追加进对面收缓冲,recv(n) 从自己收缓冲取最多 n 字节(拿到多少算多少,recv 交回 b"" 表示对面关了)。

贯穿的应用层协议(一行一命令、按换行切):req(*parts) 用空格连、末尾加换行;decode(line) 拆成 (命令, 参数表);handle(store, line)PUT k v→OK、GET k→值或 NONE、DEL k→OK/NONE、其它→ERR。

客户端:send_req(cli,*parts) 发一条;read_reply(cli) 收一行回复去掉换行;roundtrip(net,port,store,*parts) 一次完整来回。

import collections


class Net:
    def __init__(self):
        self.listeners = {}


class Endpoint:
    def __init__(self, name):
        self.name = name
        self.rbuf = b""
        self.peer = None
        self.peer_closed = False
        self.closed = False

    def send(self, data):
        if self.closed or self.peer is None:
            raise BrokenPipeError("连接已关")
        self.peer.rbuf += bytes(data)
        return len(data)

    def sendall(self, data):
        self.send(data)

    def recv(self, bufsize):
        if self.rbuf:
            out, self.rbuf = self.rbuf[:bufsize], self.rbuf[bufsize:]
            return out
        if self.peer_closed:
            return b""
        raise BlockingIOError("暂时没有数据(真 socket 会在这里阻塞等)")

    def close(self):
        self.closed = True
        if self.peer is not None:
            self.peer.peer_closed = True


class Listener:
    def __init__(self):
        self.backlog = collections.deque()

    def accept(self):
        if not self.backlog:
            raise BlockingIOError("暂时没有新连接")
        return self.backlog.popleft()


def listen(net, port):
    lis = Listener()
    net.listeners[port] = lis
    return lis


def connect(net, port):
    if port not in net.listeners:
        raise ConnectionRefusedError(111, "Connection refused")
    cli = Endpoint("client")
    srv = Endpoint("server")
    cli.peer = srv
    srv.peer = cli
    net.listeners[port].backlog.append(srv)
    return cli


def req(*parts):
    return (" ".join(parts) + "\n").encode()


def decode(line):
    bits = line.decode().split(" ")
    return bits[0], bits[1:]


def handle(store, line):
    # PUT k v -> OK;GET k -> 值 or NONE;DEL k -> OK/NONE;别的 -> ERR
    cmd, args = decode(line)
    if cmd == "PUT" and len(args) == 2:
        store[args[0]] = args[1]
        return b"OK\n"
    if cmd == "GET" and len(args) == 1:
        return (store.get(args[0], "NONE") + "\n").encode()
    if cmd == "DEL" and len(args) == 1:
        return (b"OK\n" if store.pop(args[0], None) is not None else b"NONE\n")
    return b"ERR\n"


def send_req(cli, *parts):
    # 客户端发一条请求:用空格连、末尾加换行
    cli.sendall((" ".join(parts) + "\n").encode())


def read_reply(cli):
    # 收一行回复、去掉末尾换行、解码成字符串
    return cli.recv(4096).split(b"\n", 1)[0].decode()


def roundtrip(net, port, store, *parts):
    # 一次完整来回:客户端发、服务端 handle、客户端读回复
    cli = connect(net, port)
    srv = net.listeners[port].backlog[-1]
    send_req(cli, *parts)
    srv.sendall(handle(store, srv.recv(4096).split(b"\n", 1)[0]))
    return read_reply(cli)

net = Net()
lis = listen(net, 9000)
store = {}
print(roundtrip(net, 9000, store, "GET", "z"))
提交你的答案
请登录后提交答案。
去登录
代码编辑器
Ctrl + Enter 运行
本次输入:
输出:

                        
👩‍🏫
AI
💬 题目评论

全部评论