Python发送/ recv二进制数据

时间:2014-03-24 22:05:48

标签: python sockets networking

我试图在python(v3)中发送和接收二进制数据。我试图这样做的方法是在客户端,我手动创建一个字节串,然后通过套接字将其发送到服务器。在服务器端,我接收数据并手动访问各个位以解析消息。

客户端的外观如下:

remoteIP = "164.107.112.72"
remotePort = 34562
remoteStruct = remoteIP.split('.', 4)
remoteIPBytes = ((int)(remoteStruct[0])).to_bytes(1, byteorder='little') + ((int)(remoteStruct[1])).to_bytes(1, byteorder='little') + ((int)(remoteStruct[2])).to_bytes(1, byteorder='little') + ((int)(remoteStruct[3])).to_bytes(1, byteorder='little')

headerStruct = remoteIPBytes + remotePort.to_bytes(2, byteorder='little')
sequenceNum = 0
size = #filesize

data = headerStruct + sequenceNum.to_bytes(1, byteorder='little') + (1).to_bytes(1,byteorder='little') + size.to_bytes(4, byteorder='little')
#data is then sent to server

这是服务器处理数据的方式:

serversock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)   # UDP Datagram
host = '164.107.112.70'
serversock.bind((host, localPort))

seqNum = 0

#get size
size = 0
var = serversock.recvfrom(12)
seqNum = int.from_bytes((str(var))[6], byteorder='little')

在最后一行代码中,我得到一个错误,说(str(var))被视为unicode字符串而不是二进制字符串。但是,如果我不作为字符串强制转换,我会获得一个超出范围的访问错误。

有人可以向我解释一下在python中发送和接收二进制数据的正确方法是什么?我在发送数据之前/之后尝试使用struct.pack和unpack,但是在解包时我总是遇到错误,即使格式字符串相同

1 个答案:

答案 0 :(得分:0)

  

(int)(remoteStruct[0])

这看起来很像一些C代码。 Python没有像C这样的类型转换器。

int指的是一个对象。你使用它的方式就是调用它 - 就像它是一个函数一样。

而是写一些像int(remoteStruct[0])这样的东西。你写的是有效的,因为额外的括号完全是多余的,不会改变含义。不过,这不仅仅是语法上的差异。这是两种语言类型系统的基本区别。

这与你的问题无关。

IPBytes = ((int)(remoteStruct[0])).to_bytes(1, byteorder='little') + ((int)(remoteStruct[1])).to_bytes(1, byteorder='little') + ((int)(remoteStruct[2])).to_bytes(1, byteorder='little') + ((int)(remoteStruct[3])).to_bytes(1, byteorder='little')

这是将IPv4地址打包成四个字节的令人难以置信的详细方法。试试这个:

import socket
print socket.inet_pton(socket.AF_INET, "1.2.3.4")

虽然这与你的问题没有直接关系。

IndexError问题的来源(我猜你遇到的例外,你说“访问越界错误”这不是Python内置类型中实际存在的东西 - 不是' t释义错误,逐字引用它们很可能在附近的某处:

var = serversock.recvfrom(12)

注意recvfrom的返回值:返回值是一对(字节,地址)

如果您尝试在6处为此对象编入索引,那么您肯定会收到IndexError,是的。

使用str获取此对的unicode字符串表示形式并不会真正有用 - 尽管它可能会阻止索引操作失败,因为生成的unicode字符串可能足够长。 :)不过,你会得到垃圾。

相反,请尝试索引到您读取的字节:

data, addr = serversock.recvfrom(12)

if len(data) > 6:
    seqNum = ord(data[6])

请注意,您确实需要注意长度检查。仅仅因为你将12传递给recvfrom并不意味着它返回12个字节。这意味着它返回最多 12个字节。当有人向您发送短数据报时,您不希望程序在未处理的异常中爆炸。