要认识到的一点是,TCP是一个字节流。您从TCP获得的保证是您发送的字节将以相同的顺序到达。如果字节流表示一系列命令,则不能保证字节将以与您发送的内容对齐的块形式到达。 您可能会发送:“执行”,“命令” 并接收“e”“xecuteco”“mmand”。
(是的,这是非常不可能的,但由于nagle算法的缘故,接收“executecommand”的可能性很大,但我离题了一点,就是为了编写健壮的代码,你的数据分成小块)
因此,你需要决定的第一件事情是请求字节流如何分割成请求,以及响应字节流如何分割成响应。在请求内部,您需要确定其内部结构。
假设你决定该请求看起来像: “动词参数1参数2 ...... paramN \ n”个 即:
- 请求是不换行字节序列,然后是换行符
- 该请求是由一个初始动词(非空格字符),接着是零个或多个参数
由于协议本身现在有超过TCP的附加层,则最好使用abstracti来编码这上。一些类似于:
class Request(object):
def __init__(self, verb, *args):
self.verb = verb
self.args = [str(x) for x in args]
class Client(object):
def __init__(self, sock):
self.sock = sock
self.rxbuf = ''
def send_request(self, req):
req_str = req.verb
if req.args:
req_str += ' ' + ' '.join(req.args)
req_str += '\n'
self.sock.sendall(req_str.encode("utf-8"))
class Server(object):
def __init__(self, sock):
self.sock = sock
self.rxbuf = ''
def read_request(self):
while True:
s = self.rxbuf.split('\n', 1)
if len(s) == 2:
req_str = s[0]
self.rxbuf = s[1]
req_lst = req_str.split(' ')
return Request(req_lst[0], *req_lst[1:])
data = self.sock.recv(BUF_SIZE).decode("utf-8")
self.rxbuf += data
当然,这必须通过的回答将如何看起来像,以及如何将输入的字节流描绘成响应序列的决定的补充。我试图让这段代码的主要观点是,
- 你读取的字节
- 你积累他们
- 尝试看看,如果到目前为止,你已经得到了的东西是一个完整的请求
- 如果是的话 - 分析,并将其余的下一次
这假设请求相当小,你不必流它们,这是一个更高级的话题。
@ 3D1T0R在这种情况下,我得到一个字符串“execute \ n {command}”,但仍然在同一个'data'变量中。 –