Python:“Unmask”一个d的长XOR'd字符串

2024-10-01 04:59:34 发布

您现在位置:Python中文网/ 问答频道 /正文

作为WebSocket spec的一部分,所有客户端发送的帧必须使用4字节掩码屏蔽帧的有效负载部分。在C++中,这将是非常容易的:

for (size_t i = 0; i < length; i++) {
    data[i] ^= mask[i % 4];
}

遗憾的是,Python字符串是不可变的,我宁愿避免这样做,因为字符串缓冲区的不断复制和重新创建:

^{pr2}$

经过一番研究,我发现了一个:

m = itertools.cycle(mask)
frame = ''.join(chr(ord(x) ^ ord(y)) for (x,y) in itertools.izip(oldFrame, m))

在CPython中,这将解密所需的时间减少了一半。在PyPy中,对于一个16MB掩码字符串,这很容易增长到1.5GB的RAM使用量,之后它开始交换,我不得不终止它。CPython只为16MB字符串使用150mbram(需要20秒),但这仍然很糟糕。相比之下,我的C++基准测试在0.05秒内完成,没有内存开销。在

当然,一旦软件进入生产模式,这些极端情况就不会发生(所有传入数据的上限为10KB),但我真的希望在这个基准测试中有一个好的分数。在

有什么想法吗?唯一的要求是:CPython和PyPy都很快,并且内存使用率很低。不必保留原始字符串。在

一些测试代码适用于那些想做实验的人:

import os, time

frame = os.urandom(16 << 20)
mask = os.urandom(4)

def unmask(oldFrame, mask):
    # Do your magic
    return newFrame

for i in range(0, 3): # Run several times, to help PyPy's JIT compiler
    startTime = time.time()
    f = unmask(frame, mask)
    endTime = time.time()
    print 'This run took %.3f seconds' % (endTime - startTime)

Tags: 内存字符串infortimeos基准mask
2条回答

您还可以考虑使用numpy,这将允许您在numpy中将操作卸载到高效的C代码中。当numpy不可用时,method that websockify uses使用支持可变字节数组的数组模块时,这是一个回退到较慢方法的method that websockify uses。在

改用bytearray,它是可变的。在

frame = bytearray(frame)
for i in range(len(mask)):
    frame[i] ^= mask[i]

相关问题 更多 >