システム開発の現場では、ソケット通信を用いて他のシステムと情報を連携することがあります。スマホゲームやメールや SNS など、現代の IT に通信処理は欠かせないものとなっています。この記事では、Java でソケット通信を実装する方法について解説していきます。
ソケット通信とは
ソケット通信とは、異なる機器やアプリケーションが、相互に通信を行うための仕組みで、OSI 参照モデルでいうとトランスポート層に位置付けられているプロトコルです。
普段よく使う HTTP やメールなどの通信は、OSI 参照モデルのアプリケーション層で行われており、これらは下位レイアのソケット通信に通信フォーマットなどのプロトコルが定められたものです。
このように、ソケット通信は TCPプロトコルを用いた通信全般のことを指し、HTTP やメールなどの通信を行うための土台になっています。
Javaでソケット通信する用途とは?
Java で HTTP やメール、FTP通信を行う時は、アプリケーション層レベルでのクラスが用意されているため、下位のレイアにあたるソケット通信の部分を意識する必要はなく、基本的には Java SDKに用意されているクラスを使うのが一般的です。
ソケット通信を利用するシーンとしては、例えば製造業で使用する製作機械などは、独自の通信プロトコルを使って TCP でデータのやり取りをすることが多いため、そういった時に Java でソケット通信の処理を行うことや、スマホアプリなどを初めとするゲームなどでも、できるだけ通信量を減らすために、あえて HTTP などのプロトコルを用いずに、独自の通信プロトコルによって情報量をコンパクトするためソケット通信を使用したりします。
ソケット通信を実装してみよう
それでは、 Java でソケット通信を行うための具体的なサンプルコードを作っていきましょう。ソケット通信は、特定の TCP ポートを解放し、そのポートへの接続を待ち受けるサーバー側の処理と、そこに接続を行うクライアントの処理があります。
サーバー側の実装
まずは、サーバー側の実装をしていきます。サーバー側の処理の流れは大まかに次のようになります。
- サーバーソケットを作成
- クライアントからの接続待機(accept)
- クライアントとのメッセージのやりとり
- 次のクライアントからの接続を待ち受け
上の流れを踏まえて、サンプルコードを見てみましょう。
今回、「3. クライアントとのメッセージのやりとり」の部分は、クライアントから送信されたメッセージをコンソールに出力し、exit というコマンドが送信されるまで、応答メッセージに Please input: という文字を返す単純な作りになっています。
import java.io.*;
import java.net.*;
public class Main {
public static void main(String[] args) {
// -----------------------------------------
// 1.TCPポートを指定してサーバソケットを作成
// -----------------------------------------
try (ServerSocket server = new ServerSocket(10000)) {
while (true) {
try {
// -----------------------------------------
// 2.クライアントからの接続を待ち受け(accept)
// -----------------------------------------
Socket sc = server.accept();
System.out.println("クライアントからの接続がありました。");
BufferedReader reader = null;
PrintWriter writer = null;
// -----------------------------------------
// 3.クライアントからの接続ごとにスレッドで通信処理を実行
// -----------------------------------------
try {
// クライアントからの受取用
reader = new BufferedReader(new InputStreamReader(sc.getInputStream()));
// サーバーからクライアントへの送信用
writer = new PrintWriter(sc.getOutputStream(), true);
// クライアントから「exit」が入力されるまで無限ループ
String line = null;
while (true) {
// クライアントから送信されたメッセージを取得
line = reader.readLine();
if (line.equals("exit")) {
break;
}
System.out.println("クライアントからのメッセージ=" + line);
writer.println("Please input:");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// リソースの解放
if (reader != null)
reader.close();
if (writer != null)
writer.close();
if (sc != null)
sc.close();
}
} catch (Exception ex) {
ex.printStackTrace();
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
クライアントの実装
次に、クライアント側の実装をしていきましょう。クライアントは、サーバー側で解放した TCP ポート(今回は 10000)に対して接続を行い、メッセージの送信を行います。
今回は、キーワードで入力された文字をサーバー側に送信し、exit が入力されるまで処理を繰り返すクライアントを作成します。
import java.io.*;
import java.net.*;
public class SocketClient {
public static void main(String[] args) {
// クライアントソケットを生成
try (Socket socket = new Socket("localhost", 10000);
PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// キーボード入力用のリーダーの作成
BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in))) {
// 「exit」を入力するまで繰り返し
while (true) {
System.out.print("IN>");
String input = keyboard.readLine();
writer.println(input);
if (input.equals("exit")) {
break;
}
System.out.println("[サーバーからの応答]" + reader.readLine());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
まとめ
今回は、HTTP や FTP などのアプリケーション層よりも下位のレイアで通信を行う、ソケット通信について解説してきました。
HTTP通信が主流になった昨今においては、ソケット通信をあまり使う機会が少なくなったかもしれませんが、通信データの削減や、相手からの応答を確実に検知したい時など、今でもソケット通信を利用するケースは残っているため、覚えておいて損はないでしょう。
上のサンプルコードは、処理の流れを分かりやすくするため、クライアントとのメッセージのやりとりの部分をメインのスレッド上で行っていますが、通常は複数のクライアントからの接続を待ち受けて、同時に処理を行う必要があるため、クライアントとのやりとり部分はスレッド化します。