9

私は websocket サーバーを作成しており、マスクを解除する必要があるマスクされたデータを処理する必要があります。

マスクは unsigned char[4] で、データも unsigned char* バッファです。

私はバイトごとに XOR したくありません。一度に 4 バイトずつ XOR したいのです。

uint32_t * const end = reinterpret_cast<uint32_t *>(data_+length);
for(uint32_t *i = reinterpret_cast<uint32_t *>(data_); i != end; ++i) {
    *i ^= mask_;
}

この状況で reinterpret_cast を使用すると何か問題がありますか?

別の方法は、明確ではなく、高速ではない次のコードです。

uint64_t j = 0;
uint8_t *end = data_+length;
for(uint8_t *i = data_; i != end; ++i,++j) {
    *i ^= mask_[j % 4];
}

私は、C++ 11 の機能に依存するものを含め、代替案に耳を傾けています。

4

2 に答える 2

8

投稿されたアプローチに関するいくつかの潜在的な問題は次のとおりです。

  1. 一部のシステムでは、より大きなタイプのオブジェクトにcharアクセスするには、適切に位置合わせする必要があります。の一般的な要件uint32_tは、オブジェクトが4で割り切れるアドレスに位置合わせされていることです。
  2. length / sizeof(uint32_t) != 0ループが終了しない可能性がある場合。
  3. システムのエンディアンに応じて、mask異なる値を含める必要があります。mask適切な配列で生成された場合*reinterpret_cast<uint32_t>(char_mask)、これは配列であってはなりません。

これらの問題が解決されれば、reinterpret_cast<...>(...)あなたが持っている状況で使用することができます。ポインタの意味を再解釈することは、この操作が存在する理由の1つであり、場合によっては必要になります。ただし、コードを別のプラットフォームに移植するときに問題を突き止める必要がないように、適切に機能することを確認するための適切なテストケースを作成します。

個人的には、プロファイリングで遅すぎることが示されるまで、別のアプローチを採用します。

char* it(data);
if (4 < length) {
    for (char* end(data + length - 4); it < end; it += 4) {
        it[0] ^= mask_[0];
        it[1] ^= mask_[1];
        it[2] ^= mask_[2];
        it[3] ^= mask_[3];
    }
}
it != data + length && *it++ ^= mask_[0];
it != data + length && *it++ ^= mask_[1];
it != data + length && *it++ ^= mask_[2];
it != data + length && *it++ ^= mask_[3];

私は間違いなくソフトウェアで多くの同様のアプローチを使用していますが、これは本当に高速であることを意味し、それらが顕著なパフォーマンスの問題であるとは思っていません。

于 2012-12-30T23:56:58.610 に答える
2

reinterpret_castこの場合、特に問題はありません。しかし、気をつけてください。

ペイロードのサイズが32ビットの倍数でない場合に対応していないため、現状の32ビットループは正しくありません。2つの可能な解決策、私は推測します:

  • !=forループチェックでwithを置き換え<(人々が使用する理由があります<が、それは彼らが愚かだからではありません...)、末尾の1〜3バイトをバイト単位で実行します
  • ペイロード部分のバッファのサイズが32ビットの倍数になるようにバッファを配置し、余分なバイトをXORします。(おそらく、コードは呼び出し元にバイトを返すときにペイロードの長さをチェックするので、これは問題ではありません。)

さらに、コードの構造によっては、一部のCPUのデータアクセスのずれに対処する必要がある場合もあります。フレーム全体、ヘッダー、およびすべてが32ビットで整列されたバッファーにバッファリングされており、ペイロードの長さが<126バイトまたは> 65,535バイトの場合、マスキングキーとペイロードの両方が不整列になります。

価値があるものは何でも、私のサーバーは最初のループのようなものを使用します。

for(int i=0;i<n;++i)
    payload[i]^=key[i&3];

32ビットオプションとは異なり、これは基本的に間違えることはありません。

于 2012-12-30T23:54:26.777 に答える