Python 发送/接收二进制数据
我正在尝试在Python(3版)中发送和接收二进制数据。我现在的做法是,在客户端手动创建一个字节字符串,然后通过套接字发送到服务器。在服务器端,我接收到数据后,手动访问每一个比特来解析消息。
这是客户端的代码:
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 个回答
(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的内置类型中并不存在——不要改写错误信息,直接引用原文)很可能在以下代码附近:
var = serversock.recvfrom(12)
注意 recvfrom 的返回值:返回值是一个元组 (bytes, address)。
如果你尝试在这个对象中索引 6
,那么你肯定会遇到 IndexError
。
使用 str
来获取这个元组的Unicode字符串表示并不会真的帮上忙——虽然这可能会防止索引操作失败,因为得到的Unicode字符串可能会足够长。:) 但你得到的内容可能会是垃圾。
相反,试着索引你读取的字节:
data, addr = serversock.recvfrom(12)
if len(data) > 6:
seqNum = ord(data[6])
注意这里你真的需要小心长度检查。仅仅因为你传递了 12
给 recvfrom
并不意味着它会返回12个字节。它的意思是返回最多 12个字节。你不想让你的程序在第一次有人给你发送短数据包时就因为未处理的异常而崩溃。