对面关了吗

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

客户端关掉后,服务端 closed(srv) 交回什么?

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

断连与错误:recv_line(sock) 攒到换行为止交回这一行;closed(sock) 判对面关没;safe_send(sock,data) 对面已关就不发、交回 False。

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 recv_line(sock):
    # 攒字节到一个换行为止,交回这一行(不含换行);对面关了又没换行,交回已收到的
    buf = b""
    while True:
        try:
            chunk = sock.recv(4096)
        except BlockingIOError:
            return buf
        if not chunk:
            return buf
        buf += chunk
        if b"\n" in buf:
            return buf.split(b"\n", 1)[0]


def closed(sock):
    # 对面关了吗(recv 交回空就是关了)
    return sock.peer_closed and not sock.rbuf


def safe_send(sock, data):
    # 对面已关就别发(返回 False),否则发出去返回 True
    if sock.closed or sock.peer_closed:
        return False
    sock.sendall(data)
    return True

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

                        
👩‍🏫
AI
💬 题目评论

全部评论