顺序服务:谁等谁

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

(每道题开头都有同一段:上面的内存版 TCP。)

贯穿全条的内存版 TCP(判题机不联网;接口和真 socket 一样,真机上把它换成 socket.socket() 就是真的):

net = Net()
lis = listen(net, 9000)      服务端开监听
cli = connect(net, 9000)     客户端连上——交回客户端这一头;服务端那一头进 accept 队列
srv = lis.accept()           服务端领一条新连接(一个新端点,lis 继续监听)
cli.sendall(b"...") / srv.recv(n)   send 把字节追加进对面的收缓冲;recv 从自己的收缓冲拿最多 n 字节——拿到多少算多少,不保证是「一条消息」
x.close()                    关了之后,对面 recv 交回 b"";收缓冲空又没关时 recv 抛 BlockingIOError(真 socket 在这儿会阻塞等)

单线程按队列顺序服务:三个客户端 A/B/C 先后连上,服务端一条条处理。打印处理顺序,以及处理 A 时队列里还排着几个:

import collections


class Net:
    """内存版的网络:端口 -> 监听者。判题机不联网,接口和真 socket 一样,真机上把这些换成 socket.socket() 就是真的。"""
    def __init__(self):
        self.listeners = {}


class Endpoint:
    """一条连接的一头:自己的收缓冲 rbuf,写就写进对面的 rbuf。"""
    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                      # 字节流:给你缓冲里现有的,最多 bufsize,不保证是「一条消息」
        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("暂时没有新连接(真 socket 会在 accept 阻塞)")
        return self.backlog.popleft()       # 交回服务端那一头的 Endpoint


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


def connect(net, port):
    """建一对相连的端点:客户端这头交回给调用方,服务端那头塞进监听队列等 accept。"""
    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

net = Net()
lis = listen(net, 9000)
for name in [b"A", b"B", b"C"]:
    connect(net, 9000).sendall(name)
order = []
queued_when_first = len(lis.backlog) - 1
while lis.backlog:
    conn = lis.accept()
    order.append(conn.recv(100).decode())
    conn.close()
print("".join(order) + "/" + str(queued_when_first))
提交你的答案
请登录后提交答案。
去登录
代码编辑器
Ctrl + Enter 运行
本次输入:
输出:

                        
👩‍🏫
AI
💬 题目评论

全部评论