连一下拿到回声

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

按内存版 TCP,客户端连上 echo 服务、发 hi,服务器 echo 后客户端收到什么?

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

echo:echo_once(srv) 收一段原样回一段、交回回了多少字节(对面关交回 0);serve_echo(srv) 一直回到对面关、交回总字节。

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 echo_once(srv):
    # 收一段、原样回一段;交回回了多少字节(对面关了交回 0)
    data = srv.recv(4096)
    if not data:
        return 0
    srv.sendall(data)
    return len(data)


def serve_echo(srv):
    # 一直 echo 到对面关;交回总共回了多少字节
    total = 0
    while True:
        n = echo_once(srv)
        if n == 0:
            return total
        total += n

net = Net()
lis = listen(net, 9000)
cli = connect(net, 9000)
srv = lis.accept()
cli.sendall(b"hi")
echo_once(srv)
print(cli.recv(100).decode())
提交你的答案
请登录后提交答案。
去登录
代码编辑器
Ctrl + Enter 运行
本次输入:
输出:

                        
👩‍🏫
AI
💬 题目评论

全部评论