【问题标题】:How to receive data and use it on if () statement?如何接收数据并在 if() 语句中使用?
【发布时间】:2018-06-28 01:05:05
【问题描述】:

我已尝试通过 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 ..”效果很好)

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

我该怎么办?谢谢!

【问题讨论】:

  • A TCP socket is just a stream of bytes, not a stream of messages. 当您调用client.recv(2048) 时,您可能会从客户端获得send 的前两个字节,或者整个内容,或者一个send 的最后一部分,两个更多sends,以及第四部分的第一部分。所以,它不太可能等于/disconnect
  • 如果你想用 TCP 处理消息而不是字节,你必须想出一个消息帧协议。最简单的一种是,每条消息都是一堆以b'\n' 结尾的字节,或者是一堆以UTF-8 编码'\n' 结尾的UTF-8 编码字符。如果您的消息可以包含嵌入的换行符,这将不起作用,但如果不能,则非常容易,尤其是因为 socket 对象上的 makefile 方法为您完成了整个协议的实现。
  • 如果您不确定这是否是问题所在,请尝试将print(repr(data)) 添加到服务器并查看打印结果。如果你得到'/disco''/me is leaving\n/disconnect' 或类似的东西,那是你的问题,它是this question 的重复(以及我们可以查找和添加的其他各种)。如果您得到不同的东西,那么您可能那个问题之上还有另一个问题,但除非您向我们展示您得到的东西,否则我们无法调试它。 (如果相关,查看示例客户端和示例用户输入也将有所帮助。)
  • 写下你的端口:21 主机名:DESKTOP-7G40JN7 服务器监听:(my_ip):21(phone_ip):已连接! (phone_ip) : 'dmdk\r\n' (phone_ip) : 'hey\r\n' # 输出 "hey"
  • 这甚至不包含/discconnect 流中的任何位置。那么,您为什么认为 data == "/disconnect" 是真的呢?

标签: python


【解决方案1】:

你有两个问题,你需要解决它们。


首先,a TCP socket is just a stream of bytes。当您执行recv 时,您不会收到来自另一侧的send 发送的确切消息,您将获得此刻缓冲区中的任何内容——可能是两条消息,或一半一条消息,或其他任何东西。当您只是在负载不重的计算机上使用 localhost 连接进行测试时,在许多平台上,它会在超过 99% 的时间内完成您希望的事情——但这只会使问题难以调试,它不修复它。而且,一旦您尝试通过 Internet 访问相同的代码,它大部分时间就会开始失败,而不是很少。

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

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


碰巧,您可以通过使用makefile 方法为您提供一个可以迭代的文件对象或readline on 等来解决这两个问题,就像您使用@987654331 的文件一样@来自磁盘,你可能已经知道如何处理了。

但是值得学习如何做这些事情,所以我会告诉你如何手动做。关键是你保留一个缓冲区,将每个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 消息之前与互联网断开连接,您不希望永远旋转和读取任何内容,而是要将其视为断开连接。

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

【讨论】:

    猜你喜欢
    • 2020-05-01
    • 2015-11-13
    • 2017-01-20
    • 2018-04-24
    • 2017-08-30
    • 1970-01-01
    • 2015-10-03
    • 2015-01-26
    • 1970-01-01
    相关资源
    最近更新 更多