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

时间:2017-08-10 16:27:11

标签: 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":
    command = client.recv(BUFF_SIZE).decode("utf-8").strip()
    ...

但我在'data'变量中得到“execute {command}”字符串,并且==“执行”条件未得到满足。我是客户端 - 服务器应用程序的新手,不知道如何正确地完成它。我做错了什么?

2 个答案:

答案 0 :(得分:4)

要意识到的是TCP是字节流。从TCP获得的保证是您发送的字节将以相同的顺序到达。如果字节流表示一系列命令,则无法保证字节将以与您发送的内容对齐的块的形式到达。 您可以发送:"执行","命令" 并且接收" e" " xecuteco" " mmand"

(是的,那是非常不可能的,而接收" executecommand"极有可能,因为nagle算法,但我离题了。重点是,为了编写健壮的代码,你是不要假设任何关于TCP如何将数据分成碎片的事情)

因此,首先需要确定的是请求字节流如何分区为请求,以及响应字节流如何分区为响应。在请求中,您需要决定其内部结构。

让我们假设您确定请求如下: "动词param1 param2 ... paramN \ n" 那就是:

  1. 请求是一系列非换行字节,后跟换行符
  2. 请求由初始动词(非空格字符)后跟零个或多个参数
  3. 组成

    由于协议本身现在在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. 如果是 - 分析并留下其余时间
    5. 这假设请求相当小,而且您不必对它们进行流式处理,这是一个更高级的主题。

答案 1 :(得分:0)

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

来解决此问题
if data.split("{")[0] == "execute"

说明:

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

打印

"execute"

由于data是一个字符串,您可以使用split方法使用" {"字符。

这样:

data.split("{")

将返回

["execute", "commmand}"]

因为你想要"执行"你在列表中取索引0