【问题标题】:Python Sockets - Sending a packet to a server and waiting for a responsePython Sockets - 向服务器发送数据包并等待响应
【发布时间】:2014-11-05 22:17:02
【问题描述】:

我目前正在实现以下代码,以将数据包发送到 Parallels PVA XML API。我正在尝试向服务器发送 两个 XML 数据包。第一个是指定用户凭据的登录数据包,第二个是包含有关 API 请求的信息的数据包。这些数据包应该由一个空字节\0 分隔。通常,服务器会发回多个数据包,第一个数据包说明登录成功,第二个数据包包含有关 API 请求的信息。

我遇到的问题是似乎没有发送第二个数据包。我收到的唯一响应是第一个说明登录成功的数据包,但我没有收到包含有关 API 请求信息的数据包。我认为这可能是因为我正在发送一个空字节,所以我尝试在 base64 中编码所有内容,但我最终得到了相同的结果。

那么在我看来,要么连接被关闭,服务器没有足够的时间发送它的第二个数据包,要么因为空字节而完全忽略了数据包。

任何帮助或 cmets 将不胜感激。提前谢谢!

import socket
import base64

def client(string):
    HOST, PORT = '[IP_ADDRESS]', 4433
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout(10)
    sock.connect((HOST, PORT))
    sock.send(base64.b64encode(string))
    reply = sock.recv(131072)
    sock.close()

    return reply

packet = "<packet></packet>\0<packet></packet>"
print client(packet)

请不要故意在数据包中没有信息,因为它包含敏感信息,并且IP地址被故意替换为“[IP_ADDRESS]”

【问题讨论】:

  • 服务器协议是什么?
  • @Anzel TCP - 客户端/服务器协议
  • 空字节跳过整个 131072 字节发送,因此第二部分从未到达。提供答案

标签: python python-sockets


【解决方案1】:

问题是,你试图一次发送太多字节,\0 将终止整个消息,因此剩余部分从未发送过。 我模仿了一个类似的客户端/服务器,这是响应:

Server 只是一个 echo 类型

...

客户端,您的代码稍作改动

import socket
from time import sleep
def client():
    # I change second packet to 2packet for visually distinguish the packets
    packet = "<packet></packet>\0<2packet></2packet>"
    HOST, PORT = '127.0.0.1', 4433
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout(10)
    sock.connect((HOST, PORT))
    while True:
        try:
            sock.send(packet)
            sleep(1)
            # this is the problem here
            reply = sock.recv(131072)
            if not reply:
                break
            print "recvd: ", reply
        except KeyboardInterrupt:
            print "bye"
            break
    sock.close()
    return

client()
recvd:  WelcomeOK...<packet></packet> # the null byte teminate the send and skip all remaining message
recvd:  OK...<packet></packet>
recvd:  OK...<packet></packet>
recvd:  OK...<packet></packet>
...

您会看到,2packet 从未被发送,因为它被空字节终止,消息正文超过 131072 字节,比第二部分消息正文长.

所以要解决这个问题,您只需要在每个循环上发送一个字节,因此空字节只会自行终止,并且可以发送直到消息结束的下一个字节:

通过发送单字节修改版本

... previous code
    while True:
        try:
            sock.send(packet)
            sleep(1)
            reply = sock.recv(1)
            if not reply:
                break
            print "recvd: ", reply
        except KeyboardInterrupt:
            print "bye"
            break
    sock.close()
    return

client()
recvd:  W
recvd:  e
recvd:  l
recvd:  c
recvd:  o
recvd:  m
recvd:  e
recvd:  O
recvd:  K
recvd:  .
recvd:  .
recvd:  .
recvd:  <
recvd:  p
recvd:  a
recvd:  c
recvd:  k
recvd:  e
recvd:  t
recvd:  >
recvd:  <
recvd:  /
recvd:  p
recvd:  a
recvd:  c
recvd:  k
recvd:  e
recvd:  t
recvd:  >
recvd:       # <== this null byte terminates single byte send
recvd:  <    # <== and next loop it tries to send the next byte, goal achieved
recvd:  2
recvd:  p
recvd:  a
recvd:  c
recvd:  k
recvd:  e
recvd:  t
recvd:  >
recvd:  <
...

【讨论】:

  • @Raffi,很高兴它有帮助,空字节有时有点邪恶 :)
【解决方案2】:

sock.recv 最多可以读取 131072 个字节,但它只读取 1 个字节是完全可以的。如果您立即关闭套接字,则回复将丢失。您必须重复recv,直到您阅读了服务器发送的所有信息。是否所有数据包都由\0 终止?然后阅读直到你得到预期数量的 '\0's。

【讨论】:

  • 是的,数据包由\0 终止。我尝试使用您建议的方法调试我的代码,方法是在我的控制台中输入python,而不是关闭套接字,而是等待它超时。我只是使用sock.recv(131072) 并等待它在 10 秒后超时,但它仍然会吐出一个数据包,然后是\x00。这让我相信第二个数据包甚至没有被服务器使用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-07
  • 1970-01-01
  • 2015-02-17
  • 1970-01-01
  • 2013-10-25
  • 2010-12-09
相关资源
最近更新 更多