4

WindowsでSunJavaVM 1.5または1.6を使用して、ノンブロッキングソケットを接続します。次に、ByteBuffer出力するメッセージをaに入力write()し、SocketChannelに送信しようとします。

書き込まれる量がソケットのTCP出力バッファーのスペースの量よりも大きい場合、書き込みは部分的にしか完了しないと思います(これは直感的に期待できることであり、ドキュメントについての私の理解でもあります)が、そうではありません起こります。数メガバイトであっても、write() 常に書き込まれた全量を報告するように見えます(ソケットのSO_SNDBUFは8KBで、私の数メガバイトの出力メッセージよりはるかに少ないです)。

ここでの問題は、出力が部分的に書き込まれる場合(WRITEセレクターにインタレストセットを登録しselect()、残りが書き込まれるまで待機する)を処理するコードをテストできないことです。起こる。何がわからないの?

4

6 に答える 6

7

あなたの状況に似ているかもしれない状況を再現することができました。皮肉なことに、受信者は、あなたがデータを書き込むよりも速くデータを消費していると思います。

import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class MyServer {
  public static void main(String[] args) throws Exception {
    final ServerSocket ss = new ServerSocket(12345);
    final Socket cs = ss.accept();
    System.out.println("Accepted connection");

    final InputStream in = cs.getInputStream();
    final byte[] tmp = new byte[64 * 1024];
    while (in.read(tmp) != -1);

    Thread.sleep(100000);
  }
}



import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

public class MyNioClient {
  public static void main(String[] args) throws Exception {
    final SocketChannel s = SocketChannel.open();
    s.configureBlocking(false);
    s.connect(new InetSocketAddress("localhost", 12345));
    s.finishConnect();

    final ByteBuffer buf = ByteBuffer.allocate(128 * 1024);
    for (int i = 0; i < 10; i++) {
      System.out.println("to write: " + buf.remaining() + ", written: " + s.write(buf));
      buf.position(0);
    }
    Thread.sleep(100000);
  }
}

上記のサーバーを実行してから、上記のクライアントに 128 kB のデータの 10 チャンクの書き込みを試行させると、すべての書き込み操作がブロックされることなくバッファー全体を書き込むことがわかります。ただし、接続から何も読み取らないように上記のサーバーを変更すると、クライアントでの最初の書き込み操作のみが 128 kB を書き込み、その後のすべての書き込みでは が返されることがわかります0

サーバーが接続から読み取っている場合の出力:

to write: 131072, written:  131072
to write: 131072, written:  131072
to write: 131072, written:  131072
...

サーバーが接続から読み取っていない場合の出力:

to write: 131072, written:  131072
to write: 131072, written:  0
to write: 131072, written:  0
...  
于 2008-10-01T16:12:16.763 に答える
2

私は Java で UDP を使用してきましたが、Java NIO 全般で、非常に「興味深い」完全に文書化されていない動作を見てきました。何が起こっているのかを判断する最善の方法は、Java に付属のソースを調べることです。

また、IBM などの他の JVM 実装で、探しているもののより良い実装を見つけることができることにかなり賭けたいと思いますが、それらを自分で調べずに保証することはできません。

于 2008-10-01T15:27:17.260 に答える
0

どこにも文書化されていませんが、IIRC [1]、send()は、a)提供されたバッファーを完全に送信するか、b)失敗することが保証されています。送信が部分的に完了することはありません。

[1]複数のWinsock実装(Win 3.0、Win 95、Win NTなど)を作成したので、これは(汎用ソケットではなく)Winsock固有の動作である可能性があります。

于 2012-04-02T08:56:10.830 に答える
0

私は大きな飛躍を遂げ、Javaの基盤となるネットワークプロバイダーはCの場合と同じであると想定します... O/SSO_SNDBUFはすべてのソケットに多くを割り当てます。送信コードをfor(1,100000)ループに入れると、最終的には、要求された値よりも小さい値で成功する書き込みが得られると思います。

于 2008-10-01T15:16:08.957 に答える
0

MINAGrizzlyなどの NIO フレームワークを検討する必要があります。私はエンタープライズ チャット サーバーで MINA を使用して大成功を収めました。Openfireチャット サーバーでも使用されます。Grizzly は、Sun の JavaEE 実装で使用されます。

于 2008-10-02T02:36:16.060 に答える
0

データはどこに送信されますか?ネットワークは、SO_SNDBUF とレシーバーの SO_RCVBUF を足したサイズ以上のバッファーとして機能することに注意してください。アレクサンダーが述べたように、これを受信者による読み取りアクティビティに追加すると、大量のデータを吸収できます。

于 2008-10-02T17:30:57.143 に答える