为什么此输入被另一个输入重叠?

时间:2018-07-26 16:52:40

标签: python sockets

我已经在Python 2.7.10中制作了一个TCP Server,一旦输入用户名,就要求输入密码,而不是说

  

用户名:管理员

     

密码:管理员

  

用户名:管理员

     

密码:昵称:

昵称是密码后的输入 这是相关代码:

    def username(conn, prefix="Username: "):
        conn.send(prefix)
        return conn.recv(512)

    def password(conn, prefix="Password: "):
        conn.send(prefix)
        return conn.recv(512)

    def nickname(conn, prefix="Nickname: "):
        conn.send(prefix)
        return conn.recv(512)

    username = username(conn)
    password = password(conn)
    nickname = nickname(conn)

出了什么问题?

1 个答案:

答案 0 :(得分:0)

您没有显示连接另一端正在发生的情况。但是,我很确定问题是您没有正确地区分收到的不同邮件的边界。例如,假设一侧执行此操作:

s.send('Hello')
s.send('Again')
s.send('Once More')

另一边执行:

first = s.recv(512)
second = s.recv(512)
third = s.recv(512)

这里很可能发生的情况是,第一个recv将接收所有三个数据块('HelloAgainOnce More'),然后接收方将挂起第二个recv为发送系统发送更多数据。但请注意,第一个recv获得'Hel',第二个recv获得{{1 }},第三个获取'l',其余字节留在传输中的某个地方(最终在接收系统的内核缓冲区中排队)。还有许多其他可能的结果。

这里的重点是,在使用TCP流套接字时必须提供自己的消息边界。 TCP从一个对等方传送数据。 'o'调用不能保证应用程序预期的任何边界,而且通常不会。

通常有两种区分消息边界的方法:

  1. 对于“基于文本的”协议,某些分隔符(例如换行符或空字节)分隔消息。 HTTP等协议使用此协议。在python中,通常是先将数据recv放入缓冲区,然后再将其拉出直到找到消息分隔符(如果找不到分隔符,请再回到recv来完成此操作) )。

  2. 对于二进制协议,该协议为每个数据块提供了显式的长度字段。在python中,这通常涉及使用recv模块,该模块允许您构造包含整数和特定大小的其他数值的二进制字段。然后一次接收精确字节数的消息(或从缓冲区消耗)(再次返回struct,直到获得给定消息所需的所有字节为止)。

(我应该指出,recv在技术上也是 可能没有发送其整个参数:在某些情况下,当您执行send时,仅{ {1}}已发送。您可以使用s.send('Hello')方法来解决,该方法只继续'H'直到提供的数据的所有部分都已传输。)