Java によるソケットのデータストリームの読み込みと書き込み
Java のソケットとデータストリーム
ここまでで、テキストファイル、バイナリファイル、 オブジェクトのシリアライズとデシリアライズをみてきました。
最初はナントカストリームとか、カントカリーダー・ライターとか、いろいろと紛らわしかったかもしれませんが、だいぶ慣れてきたのではないでしょうか。
ここでは、ソケットでも同じことができることをみてみようと思います。
ソケットは平たく言えば、 TCP/IP 上のデータ接続を簡単に行うための基本的なインターフェイスです。
サーバーソケットはサーバー側の接続を、クライアントソケットはクライアント側の接続を抽象化します。サーバーは接続を待ち受ける側で、クライアントは接続要求を行う側です。
ここでは簡単なサーバープログラムとクライアントプログラムを作ってネットワーク上のデータの受け渡しをしてみましょう。
Java の ServerSocket を用いたサーバープログラム
Java でのサーバーソケットは ServerSocket クラスで簡単に利用できます。
サーバーソケットは特定の IP アドレス、ポート番号上で接続要求を待ち受けます。 クライアントの接続があると accept()メソッドが返り、その時にクライアントのやりとりに使えるソケットが取得できます。
ここでは、 localhost の 0xbeef 番ポートで接続を受け付けて、 クラアントから送られてくるデータを 1 バイトずつデータを読み、 0 を受け取ったところで接続を閉じることにします。
package com.keicode.java.test;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
public class Main {
public static void main(String[] args) {
try {
System.out.println("--- Start Server ---");
System.out.println("Listening on 0xbeef");
InetAddress inetAddress = InetAddress.getByName("localhost");
ServerSocket serverSocket = new ServerSocket(
0xbeef, 50, inetAddress);
Socket socket = serverSocket.accept();
System.out.println("Accept returned");
DataInputStream inStream =
new DataInputStream(socket.getInputStream());
int i;
while ((i = inStream.read()) != -1) {
System.out.print("Read...");
if (i == 0) {
System.out.println("0. Break read-loop.");
break;
}
if (0x1F < i && i < 0x7E) {
System.out.println((char) i);
}
}
socket.close();
System.out.println("--- Exit Server ---");
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Java の Socket を使ったクライアントプログラム
上記のサーバープログラムが起動している状態で、クライアントからホストlocalhost、ポート番号 0xbeef 番に接続を行います。
サーバーは接続を待ち受けているので、クライアントが接続を試みたところで、ソケットが作成されます。
このソケットの getOutputStream() メソッドでソケットに書き込むようのストリームを取得し、 それを元に DataOutputStream を作成します。
ソケットに書き込むときには、この DataOutputStream の write() メソッドを呼ぶことで、 ソケットを経由してサーバーにデータを送信することができます。
ソケットと DataOutputStreamを使ったクライアント側プログラムは次の通りです。
package com.keicode.java.test;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
public class Main {
public static void main(String[] args) throws InterruptedException {
try {
Socket socket = new Socket("localhost", 0xbeef);
DataOutputStream outStream = new DataOutputStream(
socket.getOutputStream());
String s = "Hello!";
for (int i = 0; i < s.length(); i++) {
outStream.write(s.charAt(i));
System.out.println("Sent " + s.charAt(i));
Thread.sleep(1000);
}
outStream.write(0);
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
1秒おきに Hello! という文字列から文字を1文字ずつ、サーバーに送ります。
ソケットを用いたプログラムの動作確認
上記のプログラムを実行した結果は次のようになりました。
実行する時には、まずサーバー側のプログラムを起動しておき、それからクライアント側のプログラムを実行します。
サーバー側のプログラムの出力は次のようになります。
--- Start Server ---
Listening on 0xbeef
Accept returned
Read...H
Read...e
Read...l
Read...l
Read...o
Read...!
Read...0. Break read-loop.
--- Exit Server ---
クライアント側のプログラムは次のようになります。
Sent H
Sent e
Sent l
Sent l
Sent o
Sent !
このように、ネットワークを経由している場合でも、DataInputStream や DataOutputStream などを使うことで、 ファイルからデータを読み出す場合と同様な手順でデータを扱うことができるようになります。