2017-10-17 8 views
0

私は自分のプログラムで大きな画像を送信しようとするまで、Webソケットを介してデータを送信するチャットプログラムのために、最初からJava HTTPサーバーを作成しようとしています。 Google Chromeを使用して私は、クロムが複数のフレームのデータをサーバーに送信しているときに、データの適切な長さを送信しないことを発見しました。最初のフレームは常に問題ありませんが、最初のフレーム以降のすべてのフレームは、フレームに含まれるデータよりもかなり小さい番号を送信します。たとえば、実際に100キロバイトを超えるデータを送信しているときに123バイトのデータが含まれているというフレームを送信します。私はfirefoxやsafari(私の電話で)のような他のブラウザをテストしましたが、クロムのように大きなデータをフレームに分割しないように見えるので、同じ問題はありません。ここに私の結果のいくつかのスクリーンショットは、以下のとおりです。 初期フレーム: enter image description hereChromeで大量のデータを送信する際の問題

フレームに続いて(それが失敗した場所です): enter image description here

そしてここでは、入力ストリームからデータを取得し、私のサーバー側のコードであり、ファイルに書き込み:

byte[] headerdata = new byte[12]; 
input.read(headerdata, 0, 2); 
int frame = (headerdata[0] & 0b10000000) & 0xFF; 
long length = (headerdata[1] & 0b01111111) & 0xFF; 
System.out.format("Before: %d, Frame: %d%n", length, frame); 
if(length == 127){ 
    input.read(headerdata, 0, 12); 
    length = ((long)(headerdata[0] << 56) & 0xFFFFFFFFFFFFFFFFL | (long)(headerdata[1] << 48) & 0xFFFFFFFFFFFFFFL | (long)(headerdata[2] << 40) & 0xFFFFFFFFFFFFL | (long)(headerdata[3] << 32) & 0xFFFFFFFFFFL | (headerdata[4] << 24) & 0xFFFFFFFFL | (headerdata[5] << 16) & 0xFFFFFFL | (headerdata[6] << 8) & 0xFFFFL | headerdata[7] & 0xFFL) 
} else if(length == 126){ 
    input.read(headerdata, 6, 6); 
    length = ((headerdata[6] << 8) & 0xFFFF | headerdata[7] & 0xFF); 
}else{ 
    input.read(headerdata, 8, 4); 
} 
System.out.println("After: " + length); 

int count; 
int total = 0; 
byte[] buffer = new byte[16384]; 
boolean done = false; 
while(done == false){ 
    count = input.read(buffer, 0, buffer.length); 
    //System.out.println(count); 
    for(int i = 0; i < count; i++){ 
     buffer[i] = (byte)(buffer[i]^headerdata[(total & 3) + 8]); 
     total++; 
    } 
    fileoutput.write(buffer, 0, count); 
    System.out.format("Count: %d Left: %d%n", count, (length - total)); 
    if(total >= length){ 
     done = true; 
    } 
} 

if(frame == 128) break; 

私は、次のフレームの長さを読み取ることができないかもしれない理由についてどのような説明が大幅に(私も私自身のいくつかの疑いを持っている)いただければ幸いです。あなたの時間と努力に感謝します。

+0

ストリームの終わりか短い読み込みをチェックすることなく、 'read()'がバッファをいっぱいにしていると仮定します。 'DataInputStream.readFully()'を使ってください:実際には、これらの読み込みのいくつかは 'readInt()'とお友達で行うことができます。 – EJP

答えて

-1

バッファがオーバーフローしてデータが誤読されたり失われたりすることがわかりました。そのため、フレームから間違った長さの値を取得していました(Thanks EJP)。読み込んだバイト数がそのフレームの長さの値に近づいているかどうかを確認し、完全なバッファサイズの代わりに残っているものだけを読み取ってオーバーフローを止めるif文を追加して修正しました。ここで変更を加えたコードは次のとおりです。

byte[] headerdata = new byte[12]; 
       input.read(headerdata, 0, 2); 
       int frame = (headerdata[0] & 0b10000000) & 0xFF; 
       long length = (headerdata[1] & 0b01111111) & 0xFF; 
       System.out.format("Before: %d, Frame: %d%n", length, frame); 
       if(length == 127){ 
        input.read(headerdata, 0, 12); 
        length = ((long)(headerdata[0] << 56) & 0xFFFFFFFFFFFFFFFFL | (long)(headerdata[1] << 48) & 0xFFFFFFFFFFFFFFL | (long)(headerdata[2] << 40) & 0xFFFFFFFFFFFFL | (long)(headerdata[3] << 32) & 0xFFFFFFFFFFL | (headerdata[4] << 24) & 0xFFFFFFFFL | (headerdata[5] << 16) & 0xFFFFFFL | (headerdata[6] << 8) & 0xFFFFL | headerdata[7] & 0xFFL); 
       }else if(length == 126){ 
        input.read(headerdata, 6, 6); 
        length = ((headerdata[6] << 8) & 0xFFFF | headerdata[7] & 0xFF); 
       }else{ 
        input.read(headerdata, 8, 4); 
       } 
       System.out.println("After: " + length); 

       int count; 
       int total = 0; 
       byte[] buffer = new byte[16384]; 
       boolean done = false; 
       while(done == false){ 
        if(length - total > buffer.length) count = input.read(buffer, 0, buffer.length); 
        else count = input.read(buffer, 0, (int) (length - total)); 
        //System.out.println(count); 
        for(int i = 0; i < count; i++){ 
         buffer[i] = (byte)(buffer[i]^headerdata[(total & 3) + 8]); 
         total++; 
        } 
        fileoutput.write(buffer, 0, count); 
        //System.out.format("Count: %d Left: %d%n", count, (length - total)); 
        if(total >= length){ 
         done = true; 
        } 
       } 

       if(frame == 128) break; 

私もソケットからバイトストリームを読み込むためのさまざまな方法でいくつかの研究を行なったし、またDataInputStream.readFully()(感謝EJP)を使用することが可能であることがわかりました。

+0

あなたはまだ読み込みがバッファを満たし、*まだ*ストリームの終わりと短い読み込みを無視していると仮定しています。これを修正する必要があります。 – EJP

+0

私は混乱しています。私が共有しているコードは、フレームで送信された長さの値から正確なバイト数が読み取られるまで、読み込まれ続けます。私の問題は、読み過ぎによるもので、次のフレームのヘッダーをスキップしました。私はストリームの終わりをチェックすることができません。なぜなら、データが送信された後にwebsocketが開いたままになっているから、短い読み込みが意味することを理解できません。 – Anonymous

関連する問題