如何在Python中拆分从套接字接收的数据?

如何在Python中拆分从套接字接收的数据?,python,sockets,client-server,Python,Sockets,Client Server,我正试图用Python编写我的第一个客户机-服务器应用程序。我的客户端向服务器端发送不同的命令。例如,其中一个用于在命令shell中执行命令。它看起来像: client.send("execute".encode("utf-8")) client.send(command.encode("utf-8")) 在服务器端,我尝试通过以下方式接收: data = client.recv(BUFF_SIZE).decode("utf-8").strip() if data == "execute":

我正试图用Python编写我的第一个客户机-服务器应用程序。我的客户端向服务器端发送不同的命令。例如,其中一个用于在命令shell中执行命令。它看起来像:

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”条件未满足。我是客户机-服务器应用程序的新手,不知道如何正确地完成它。我做错了什么?

您可以通过将服务器代码上的if语句更改为:

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

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

"execute"
因为数据是一个字符串,所以可以使用split方法使用“{”字符将字符串拆分为一个列表

因此:

会回来吗

["execute", "commmand}"]

由于您希望“执行”,因此可以在列表中获取索引0,您可以通过将服务器代码上的if语句更改为:

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

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

"execute"
因为数据是一个字符串,所以可以使用split方法使用“{”字符将字符串拆分为一个列表

因此:

会回来吗

["execute", "commmand}"]

既然你想“执行”你在列表中使用索引0,要意识到的是TCP是一个字节流。你从TCP得到的保证是,你发送的字节将以相同的顺序到达。如果字节流代表一系列命令,你就不能保证字节将以与你接收的内容对齐的块的形式到达T 您可以发送:“执行”、“命令” 以及接收“e”xecuteco“mmand”

(是的,这是极不可能的,而接收“executecommand”是极有可能的,因为nagle算法,但我离题了。要点是,为了编写健壮的代码,您不能假设TCP如何将数据分解成碎片)

因此,您需要决定的第一件事是如何将请求字节流划分为请求,以及如何将响应字节流划分为响应。在请求内部,您需要决定其内部结构

假设您决定请求如下所示: “动词param1 param2…paramN\n” 即:

  • 请求是一个非换行字节序列,后跟换行符
  • 请求由一个初始动词(非空格字符)和零个或多个参数组成
  • 由于协议本身现在在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
    
    当然,这必须通过决定响应的外观以及如何将传入字节流描述为响应序列来补充

  • 你读字节
  • 你积累它们
  • 试着看看到目前为止你得到的东西是否是完整的请求
  • 如果是,请对此进行分析,其余部分留待下次使用

  • 这假设请求相当小,您不必对其进行流式处理,这是一个更高级的主题。

    需要了解的是,TCP是一个字节流。。从TCP获得的保证是,您发送的字节将以相同的顺序到达。如果字节流表示一系列命令,则您不会收到任何请求保证字节将以与您发送的内容对齐的块的形式到达。 您可以发送:“执行”、“命令” 以及接收“e”xecuteco“mmand”

    (是的,这是极不可能的,而接收“executecommand”是极有可能的,因为nagle算法,但我离题了。要点是,为了编写健壮的代码,您不能假设TCP如何将数据分解成碎片)

    因此,您需要决定的第一件事是如何将请求字节流划分为请求,以及如何将响应字节流划分为响应。在请求内部,您需要决定其内部结构

    假设您决定请求如下所示: “动词param1 param2…paramN\n” 即:

  • 请求是一个非换行字节序列,后跟换行符
  • 请求由一个初始动词(非空格字符)和零个或多个参数组成
  • 由于协议本身现在在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
    
    当然,这必须通过决定响应的外观以及如何将传入字节流描述为响应序列来补充

  • 你读字节
  • 你积累它们
  • 试着看看到目前为止你得到的东西是否是完整的请求
  • 如果是,请对此进行分析,其余部分留待下次使用

  • 这假设请求相当小,您不必流式处理它们,这是一个更高级的主题。

    不,我的意思是,我希望将这两条消息分别接收到不同的变量中。我的问题是recv函数将这两条消息放在一个“数据”中。BUFF_SIZE设置为多少?它设置为1024字节您的字节大小是pr可能太大了。使用sys.getsizeof(“execute”)获取字符串的实际字节大小。请参阅本文:我想实现一个接口,其中客户端首先发送包名,然后发送“包”的主体。例如,我想上载一个文件。首先,我说“upload_file”到服务器,之后它知道应该获取文件名及其内容。它获取名称“package”以及不同变量的以下数据。因此,包含“package name”的字符串可以具有不同的值:“execute”、“download”、“anything”…不,不,我的意思是,我希望将这两条消息分别接收到不同的变量中。我的问题是recv函数将这两条消息放在一个“数据”中。BUFF_SIZE设置为什么?它设置为1024字节您的字节大小可能太大。使用sys.getsizeof(“执行”)获取