Java Server Socketを使用してInputStreamを読み取ります

1. 概要

ネットワークを介してデータを送受信するには、しばしばソケットを使用します。 ソケットは、IPアドレスとポート番号の組み合わせに過ぎず、特定のマシンで実行されているプログラムを一意に識別できます。
このチュートリアルでは、ソケットを介して送信されたデータを読み取る方法を示します。

2. ソケットからのデータの読み取り

仮定すると、https://www.baeldung.com/a-guide-to-java-sockets [ソケットプログラミングの基本的な理解]があります。
次に、サーバーがリッスンしているポートでデータを読み取る方法をさらに詳しく見ていきます。
まず、_ServerSocket、Socket、_、および_DataInputStream_変数を宣言して初期化する必要があります。
ServerSocket server = new ServerSocket(port);
Socket socket = server.accept();
DataInputStream in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
ソケットの_InputStream_を_DataInputStream._でラップすることを選択したことに注意してください。これにより、テキスト行とJavaプリミティブデータ型を移植可能な方法で読み取ることができます。
これは素晴らしいことです。受け取るデータのタイプがわかっている場合は、* _ readChar()、readInt()、readDouble()_、_ readLine()などの特殊なメソッドを使用できます。 _*
*ただし、データのタイプと長さが事前にわからない場合は困難な場合があります。*
その場合、代わりに下位レベルの_read()_関数を使用して、ソケットからバイトストリームを取得します。 *しかし、このアプローチには小さな問題があります:取得するデータの長さとタイプをどのように知るのですか?*
次のセクションでこのシナリオを調べてみましょう。

3. ソケットからのバイナリデータの読み取り

バイト単位でデータを読み取る場合、サーバーとクライアント間の通信用に独自のプロトコルを定義する必要があります。 定義できる最も単純なプロトコルはTLV(Type Length Value)と呼ばれます。 これは、ソケットに書き込まれるすべてのメッセージがType Length Valueの形式であることを意味します。
したがって、送信されるすべてのメッセージを次のように定義します。
  • データ型を表す1 byte_文字
    like s for _String

  • データの長さを示す4 _byte_整数

  • そして実際のデータ、その長さはちょうど示された

    link:/uploads/figure1-1-1-100x40.png%20100w []
    クライアントとサーバーが接続を確立すると、各メッセージはこの形式に従います。 次に、各メッセージを解析して特定のタイプのデータの_n_バイトを読み取るコードを記述できます。
    _String_メッセージを使用した簡単な例を使用して、これを実装する方法を見てみましょう。
    まず、_readChar()_関数を呼び出してデータのタイプを読み取り、次に_readInt()_関数を呼び出してデータの長さを読み取る必要があります。
char dataType = in.readChar();
int length = in.readInt();
その後、受信したデータを読み取る必要があります。 *ここで注意すべき重要な点は、_read()_関数が1回の呼び出しですべてのデータを読み取れない場合があることです。 したがって、whileループで_read()_を呼び出す必要があります。*
if(dataType == 's') {
    byte[] messageByte = new byte[length];
    boolean end = false;
    StringBuilder dataString = new StringBuilder(length);
    int totalBytesRead = 0;
    while(!end) {
        int currentBytesRead = in.read(messageByte);
        totalBytesRead = currentBytesRead + totalBytesRead;
        if(totalBytesRead <= length) {
            dataString
              .append(new String(messageByte, 0, currentBytesRead, StandardCharsets.UTF_8));
        } else {
            dataString
              .append(new String(messageByte, 0, length - totalBytesRead + currentBytesRead,
              StandardCharsets.UTF_8));
        }
        if(dataString.length()>=length) {
            end = true;
        }
    }
}

4. データを送信するクライアントコード

*クライアント側のコードはどうですか?*実際、それは非常に簡単です:
char type = 's'; // s for string
String data = "This is a string of length 29";
byte[] dataInBytes = data.getBytes(StandardCharsets.UTF_8);

out.writeChar(type);
out.writeInt(dataInBytes.length);
out.write(dataInBytes);
クライアントが行っていることはそれだけです!

5. 結論

この記事では、ソケットからデータを読み取る方法について説明しました。 特定のタイプのデータを読み取るのに役立つさまざまな関数を調べました。 また、バイナリデータの読み取り方法も確認しました。
このチュートリアルの「完全な実装」はhttps://github.com/eugenp/tutorials/tree/master/core-java-modules/core-java-networking[on GitHub]にあります。