如何接收数据并在if()语句上使用它?

时间:2018-06-25 22:48:44

标签: python

我试图通过python 2.7上的这段代码从我的连接接收数据:

    server = socket(AF_INET, SOCK_STREAM)
    server.bind(('0.0.0.0', 21))
    server.listen(1)
    client , addr = server.accept()
    data = client.recv(2048)

当我必须打印或发送到另一个连接我的数据时,它正在工作,但是我想添加这些行:

if(data == "/disconnect") :
     <disconnect blha blha... you know >
else :
     <print the data and send it back blha blha... >

(我没有检查if语句和“ disconnect blha blha ..”效果很好)

它只是传递代码,所以当我的客户请求断开连接时,该请求将作为“原始”消息发送给服务器(服务器不会踢他)

我该怎么办?谢谢!

1 个答案:

答案 0 :(得分:0)

您有两个问题,需要同时解决。


首先,a TCP socket is just a stream of bytes。当您执行recv时,不会从另一端收到send发送的一条消息,您将获得当前缓冲区中的所有内容,可能是两个消息,半条消息或其他任何消息。当您只是在负载不重的计算机上使用本地主机连接进行测试时,在许多平台上,它将执行您希望超过99%的时间的工作,但这只会使问题难以调试,不能解决。并且,一旦您尝试通过Internet访问相同的代码,大多数情况下它就会开始失败,而不是很少。

幸运的是,客户端似乎正在以文本形式发送消息,没有任何嵌入的换行符,每条消息之间使用\r\n Windows风格的行尾。这是一个非常好的协议。您只需要编写代码即可在接收端处理该协议。

第二个问题是,即使您碰巧恰好收到一条消息send,该消息也会包含\r\n行尾。 '/disconnect\r\n' == '/disconnect'当然是错误的。因此,作为协议处理程序的一部分,您需要删除换行符。


碰巧,您可以通过使用makefile方法为您提供可以迭代或readline等的文件对象来解决这两个问题,就像处理文件一样您open从磁盘上获取的信息,您可能已经知道该如何处理。

但是值得学习如何做这些事情,因此,我将向您展示如何手动进行。关键是要保留一个缓冲区,将每个recv添加到该缓冲区中,然后将其拆分为几行,将其余部分放回缓冲区中,并将每一行作为消息处理。有更多优雅/简洁的方法可以编写此代码,但让我们简单一点吧:

buf = ''
while True:
    data = client.recv(2048)
    buf += data
    lines = buf.split('\r\n')
    buf = lines.pop()
    for line in lines:
        # line is now a single message, with the newline stripped
        if line == "/disconnect":
            # do disconnect stuff
        else:
            # do normal message stuff

这就是使基础知识正常工作所需要的。但是在真实服务器中,您还需要一些代码来处理其他两个条件-因为客户端并不总是干净地关闭。例如,如果客户端在断开连接才能发送/disconnect消息之前已断开与Internet的连接,则您不想一直旋转并永远阅读任何内容,则希望将其视为断开连接。

  • if not data:表示客户端已完成干净(在TCP级别)关闭。因此,您需要断开连接并中断接收循环。
    • 根据您的设计,仅关闭发送端并等待服务器的最终答复可能是合法的,因此您需要确保已发送完所有内容。 (这在许多互联网协议中都很常见。)
    • 关闭前不发送最终换行符甚至是合法的;如果要支持此功能,则应检查if buf:,如果是,请将buf视为最后一条命令。 (这在许多协议中并不常见,但是在客户端中是常见的错误,因此,例如,许多Web服务器都可以处理它。)
  • try: / except Exception as e:将捕获各种错误。这些错误意味着套接字不再可用(或者代码中肯定存在严重错误),因此您要通过丢弃连接并中断接收循环来解决此问题,而无需先发送任何最终响应或阅读任何最终信息。
    • 几乎总是值得以某种方式记录e(也许只是print 'Error from', addr, repr(e)),因此,如果遇到意外的异常,则需要调试。