簡體   English   中英

如何在Python中從套接字拆分接收到的數據?

[英]How to split received data from socket in Python?

我正在嘗試用Python編寫我的第一個客戶端服務器應用程序。 我的客戶端將不同的命令發送到服務器端。 例如,其中之一是用於在命令外殼中執行命令。 看起來像:

client.send("execute".encode("utf-8"))
client.send(command.encode("utf-8"))

在服務器端,我試圖通過這種方式接收它:

data = client.recv(BUFF_SIZE).decode("utf-8").strip()
if data == "execute":
    command = client.recv(BUFF_SIZE).decode("utf-8").strip()
    ...

但是我在'data'變量中得到了“ execute {command}”字符串,並且==“ execute”條件沒有得到滿足。 我是客戶機-服務器應用程序的新手,不知道如何正確執行它。 我做錯了什么?

要實現的是TCP是字節流 從TCP獲得的保證是,發送的字節將以相同的順序到達。 如果字節流表示命令序列,則無法保證字節將以與您發送的內容對齊的塊的形式到達。 您可能正在發送:“ execute”,“ command”,並接收“ e”,“ xecuteco”,“ mmand”。

(是的,這是極不可能的,而由於nagle算法,極有可能接收到“ executecommand”,但我離題了。關鍵是要編寫健壯的代碼,您無需承擔任何其他責任,而只是TCP如何將數據分解成碎片)

因此,您需要決定的第一件事是如何將請求字節流划分為請求,以及如何將響應字節流划分為響應。 在請求內部,您需要確定其內部結構。

假設您確定請求看起來像:“ verb param1 param2 ... paramN \\ n”即:

  1. 請求是非換行字節的序列,后跟換行
  2. 該請求包含一個初始動詞(非空格字符),后跟零個或多個參數

由於協議本身現在在TCP上有一個附加層,因此最好使用抽象代碼對此進行編碼。 類似於:

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

當然,這必須由決定響應看起來如何以及如何將傳入的字節流划定為響應序列的決定來補充。 我試圖用這段代碼說明的重點是

  1. 你讀字節
  2. 你積累他們
  3. 嘗試看看您到目前為止所獲得的東西是否已被全部索取
  4. 如果是,請進行分析,然后將其余的留給下次

假設請求相當小,您不必流式傳輸,這是更高級的主題。

您可以通過將服務器代碼上的if語句更改為以下內容來解決此問題:

if data.split("{")[0] == "execute"

說明:

data = "execute{command}"
print data.split("{")[0]

版畫

"execute"

由於數據是字符串,因此可以使用split方法使用“ {”字符將字符串拆分為列表。

所以:

data.split("{")

會回來

["execute", "commmand}"]

並且由於您要“執行”,因此將列表中的索引設為0

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM