1

というわけで、ちょっと大雑把ですが、できる限り絞ってみます。サーバー (EventMachine を使用) があり、パケットが分割されることもありますが、バッファリングされることもあります。そこで、それらをバッファリング/アンバッファリングする関数を作成してみました。私は何かを作ることができましたが、それは「期待どおり」に機能していません. 正直なところ、「ほとんど機能していない」とは言えません。

何よりもまず、パケット構造を指摘したいと思います。

  • パケットの最初の 4 バイトは、その ID またはパケットの名前です ( name)。
  • 次の 4 バイトは、パケットの「msg」部分の長さです ( len)。
  • また、msg 部分の前の最後の 4 バイトは参照フィールドで、さまざまな用途があります ( ref)。

注:lenfは len の生の形式なので、文字列です。それほど重要ではないと思います。


バッファコード

def split(data)
    if ($packet_buffer != "" && !$packet_buffer.nil?)
        data = $packet_buffer + data
        $packet_buffer = ""
    end
    last = 0
    packets = []
    loop do
        if data[last..-1].length < 8
            $packet_buffer = data[last..-1]
            break
        end
        name = data[last...last+=4]
        lenf = data[last...last+4]

        len = 0
        data[last...last+=4].each_byte {|b| len+=b}

        if !data[last+4..-1].nil? && data[last+4..-1].length < len
            $packet_buffer = data
            break
        end

        ref = data[last...last+=4]
        msg = data[last...last+=len]

        packets << (name << lenf << ref << msg)

        break if data[last..-1].nil?
    end
    packets
end

TLDR

Rubyでバッファリングおよびバッファ分割パケット/データ(EventMachineによって渡される)を分割する方法は?

更新:パケットは TCP 経由で送信されます。データは C で作成されたクライアントから取得されるため、バイト ストリームです。

正確に何が問題なのかはわかりませんが、このメソッドはパケットを適切に分割またはバッファリングしていないようです。少量のデータを受信して​​いる間は問題なく動作します(バッファリングも分割もされていないと思います)。

パケットがバッファリングされている場合、パケットを正常に分割することさえありますが、バッファリングがまったく機能していないようです


ここで「ロジック」の一部を台無しにしていると確信していますが、それが何であるかはわかりません。どんな助けでも大歓迎です。

ありがとう

4

2 に答える 2

1

さて、ここに私に飛び出す1つのエラーがあります:

len = 0
data[last...last+=4].each_byte {|b| len+=b}

長さを格納する形式を指定しませんでしたが、リトルエンディアン整数のlen = (len>>8) + (b<<24)場合は、現在行っているようにすべてのバイトを加算するのではなく、次のようにする必要があります。len常に 256 未満であれば、現在のアルゴリズムは正常に機能します。

ここに他の論理エラーが隠れている可能性があります。data[last..-1].nil?;のような紛らわしい表現を使用するのは好きではありません。data.lengthとを含む単純な不等式として書き直しますlast

コードを本当にクリーンアップしたい場合は、別のアプローチを取ることをお勧めしますprocess_byte。一度に 1 つずつ呼び出される新しい関数にバイトをフィードします。その関数は、必要な状態情報 (メッセージのどの部分を次に受信するかなど) を追跡し、バイトを完全なメッセージにアセンブルし、完全なメッセージを上位レベルのコードに渡します。関数はprocess_byte、バイトがどのようにパケット化されたかを認識しないため、プログラムに含まれている可能性のある特定のクラスのバグをすぐに潰すことができます。

Ruby ファイバーを使用して関数を適切な方法で実装すると、同期 (例: ) に見えても実際には非同期になるprocess_byteコードを記述できます。len += get_next_byte()

于 2011-07-03T02:15:15.313 に答える
0

わかりました、私がそれを適切に行う方法を考え出したと考える人もいます. David Graysonの助けに感謝します.

def split(data)
    packets = []
    loop do
        if !$packet_buffer.nil?
            data = $packet_buffer << data
            $packet_buffer = nil
        end

        if data.length < 8
            $packet_buffer = data
            break
        end


        len = calc_Uint32(data[4...8])

        if data.length-12 < len
            $packet_buffer = data
            break
        end

        packets << data[0...12+len]
        data[0...12+len] = ''

        break if data.length == 0
    end
    packets
end #split

それほど普遍的ではないので、誰かがそれを役に立つと思うかどうかは本当に疑問ですが、最終的には誰かがそれを使用できることを願っています.

于 2011-07-03T10:24:45.207 に答える