使用python的gzip遇到问题/"如何知道使用了什么压缩算法?
好的,我有一个开源的Java客户端/服务器程序,它通过数据包进行通信。我正在尝试为这个程序写一个Python客户端,但数据包的内容似乎是压缩过的。我快速浏览了一下源代码,发现代码中只引入了gzip这个压缩模块,所以我猜测使用的压缩方式是gzip。但是,当我从Wireshark中保存了一个数据包的数据后,尝试运行下面的代码时,
import gzip
f = gzip.open('compressed_file')
f.read()
它告诉我这不是一个gzip文件,因为头部信息不对。有人能告诉我我哪里出错了吗?我在保存的时候是不是改变了格式?在我尝试运行这个代码之前,是否需要先去掉一些多余的数据?
if (zipped) {
// XML encode the data and GZIP it.
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Writer zipOut = new BufferedWriter(new OutputStreamWriter(
new GZIPOutputStream(baos)));
PacketEncoder.encodeData(packet, zipOut);
zipOut.close();
// Base64 encode the commpressed data.
// Please note, I couldn't get anything other than a
// straight stream-to-stream encoding to work.
byte[] zipData = baos.toByteArray();
ByteArrayOutputStream base64 = new ByteArrayOutputStream(
(4 * zipData.length + 2) / 3);
Base64.encode(new ByteArrayInputStream(zipData), base64, false);
编辑:
抱歉,我这里有你们请求的信息。这些信息是通过Wireshark监听在不同电脑上运行的两个程序之间的通信收集的。为了得到下面的十六进制流,我在Wireshark中使用了“复制 -> 十六进制(字节流)”的选项。
001321cdc68ff4ce46e4f00d0800450000832a85400080061e51ac102cceac102cb004f8092a9909b32c10e81cb25018f734823e00000100000000000000521f8b08000000000000005bf39681b59c85818121a0b4884138da272bb12c512f27312f5dcf3f292b35b9c47ac2b988f902c59a394c0c0c150540758c250c5c2ea5b9b9950a2e89258900aa4c201a3f000000
我知道这个数据中会包含字符串“Dummy Data”。我相信它还应该包含“Jonathanb”(我用来发送消息的玩家名字)和整数80(根据代码,80是“聊天”命令的编号)。
3 个回答
这可能符合RFC 1950、1951或1952中的某一个标准。
因为名字是GZIP,所以我会先检查1952。接着再看看ZLIB,也就是1950。最后是DEFLATE(1951)。
DotNetZip是一个.NET库,可以让.NET应用程序读取符合这些格式的数据流。如果你有一个符合上述标准的数据流,你可以通过依次尝试使用DotNetZip的每个流来快速确定它是哪一种;比如说GZipStream、ZlibStream和DeflateStream。其中一个会成功,其他的则不会。
我不知道有没有Java库提供这些流。这并不意味着没有,只是我不知道而已。
DotNetZip是免费的,可以在Windows+Mono、Linux+Mono以及Windows+.NET上使用。
如果你能提供以下信息,会对我们帮助很大:
(0) 你是怎么得出“数据包的内容似乎被压缩了”这个结论的?
(1) 你能给出写入这些数据包的包的(a) 源代码和(b) 文档的链接吗?
(2) 能否提供一个示例数据包的内容?
(a) print repr(open('file_saved_from_wireshark', 'rb').read())
(b) 如果通过wireshark的长途旅行让事情变得复杂,可以在你的Python客户端中插入这个:
print repr(a_sample_packet)
(3) 请提供你收到的确切错误信息(复制粘贴过来)
更新:在原作者提供了一个数据包的十六进制转储后
这段代码:
import binascii, sys, cStringIO, gzip, struct, zlib
# guff is allegedly a "packet", formatted as 2 hex characters per byte
guff = "001321cdc68ff4ce46e4f00d0800450000832a85400080061e51ac102cceac102cb004f8092a9909b32c10e81cb25018f734823e00000100000000000000521f8b08000000000000005bf39681b59c85818121a0b4884138da272bb12c512f27312f5dcf3f292b35b9c47ac2b988f902c59a394c0c0c150540758c250c5c2ea5b9b9950a2e89258900aa4c201a3f000000"
guff2 = binascii.unhexlify(guff)
print "raw input: len=%d repr=%r" % (len(guff2), guff2)
# gzip spec: http://www.faqs.org/rfcs/rfc1952.html
GZIP_HDR = "\x1F\x8B\x08"
gzpos = guff2.find(GZIP_HDR)
if gzpos == -1:
print "Can't find gzip header"
sys.exit(1)
print gzpos, "bytes before gzipped data"
gzipped = guff2[gzpos:]
packet_crc, packet_orig_len = struct.unpack("<II", gzipped[-8:])
print "packet_crc, packet_orig_len:", hex(packet_crc), packet_orig_len
fobj = cStringIO.StringIO(gzipped)
zf = gzip.GzipFile(fileobj=fobj)
payload = zf.read()
print "payload: len=%d repr=%r" % (len(payload), payload)
print "crc32(payload):", hex(zlib.crc32(payload))
在使用Python 2.6.4运行时,产生了这个输出(在Windows的“命令提示符”终端中每80列换行):
raw input: len=145 repr="\x00\x13!\xcd\xc6\x8f\xf4\xceF\xe4\xf0\r\x08\x00E\x00\x
00\x83*\x85@\x00\x80\x06\x1eQ\xac\x10,\xce\xac\x10,\xb0\x04\xf8\t*\x99\t\xb3,\x1
0\xe8\x1c\xb2P\x18\xf74\x82>\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00R\x1f\x8b\x0
8\x00\x00\x00\x00\x00\x00\x00[\xf3\x96\x81\xb5\x9c\x85\x81\x81!\xa0\xb4\x88A8\xd
a'+\xb1,Q/'1/]\xcf?)+5\xb9\xc4z\xc2\xb9\x88\xf9\x02\xc5\x9a9L\x0c\x0c\x15\x05@u\
x8c%\x0c\\.\xa5\xb9\xb9\x95\n.\x89%\x89\x00\xaaL \x1a?\x00\x00\x00"
63 bytes before gzipped data
packet_crc, packet_orig_len: 0x1a204caa 63
payload: len=63 repr='\xac\xed\x00\x05w\x04\x00\x00\x00Pur\x00\x13[Ljava.lang.Ob
ject;\x90\xceX\x9f\x10s)l\x02\x00\x00xp\x00\x00\x00\x01t\x00\nDummy Data'
crc32(payload): 0x1a204caa
评论/问题:
这个数据包长145字节;那之前说的数据包大约2900字节的说法怎么回事?
这个数据包包含63字节的尚未分析的数据,后面跟着一个82字节的gzip流,这个gzip流解压后变成63字节。gzip流后面没有数据——通过比较数据包最后8个字节和计算出的gzip值来验证。它包含预期的“虚拟数据”,但用户ID“johnathonb”不在里面(或者被模糊处理或加密了)。
数据包的结构和我们猜测的代码不匹配(没有XML,没有base64)。
解压后的数据包含字符串“java.lang.Object”,这可能是某种Java序列化协议的特征。进入这里的你们,放弃一切希望吧。