要認識到的一點是,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'變量中。 –