连一下拿到回声
按内存版 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())
全部评论