Javaでネットワーク通信を書こうとすると、「ソケットのつなぎ方がわからない」「URLとURIの違いが謎」「HTTPを自前で処理するの面倒」…といった問題に直面しがちです。
私も初めてSocketやHttpURLConnectionを触ったとき、エラーと謎の例外の嵐で夜も眠れませんでした。
本記事では、ソケット通信、URL/URI、HTTPリクエスト、タイムアウト設定、IPv6対応まで、小学生にもわかるやさしい言葉とコード例で一気に解説します。
「これを読んでから、REST APIの実装がサクサク進んだ」「ついにIPv6でも動くコードが書けた」と多くの声。
Socketで「Hello」を送り、HttpURLConnectionでJSONをGET、非同期にタイムアウト付きで処理、さらにIPv6で接続してみる…すべてのステップを実例で紹介します。
この記事を最後まで読めば、Javaのネット周りの基礎がしっかり身につき、明日からの開発がグッと楽になります!
ソケット通信の基本――SocketとServerSocketを使ってみよう
ソケット通信は、コンピューター同士が手をつないでデータをやり取りする仕組みです。JavaではSocketとServerSocketクラスを使って簡単に実現できます。
Socketは“クライアント側”が使い、ServerSocketは“サーバー側”が使います。ServerSocketが待ち受けポートを開き、Socketがそこへ接続すると、両者の間でInputStream/OutputStreamを通じて文字やバイトを送受信できるのです。
まずはサーバー側の処理です。
import java.net.ServerSocket;
import java.net.Socket;
import java.io.*;
public class SimpleServer {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(5000);
System.out.println("サーバー起動: ポート5000で待機中...");
Socket client = server.accept();
BufferedReader in = new BufferedReader(
new InputStreamReader(client.getInputStream())
);
String msg = in.readLine();
System.out.println("受信メッセージ: " + msg);
client.close();
server.close();
}
}
次にクライアント側です。
import java.net.Socket;
import java.io.*;
public class SimpleClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("localhost", 5000);
PrintWriter out = new PrintWriter(
socket.getOutputStream(), true
);
out.println("Hello, Server!");
socket.close();
}
}
import java.net.Socket;
import java.io.*;
public class SimpleClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("localhost", 5000);
PrintWriter out = new PrintWriter(
socket.getOutputStream(), true
);
out.println("Hello, Server!");
socket.close();
}
}
このように、ServerSocket.accept()で接続を待ち、Socket.getInputStream()/getOutputStream()で通信します。
SocketとServerSocketを使えば、Javaでネットワーク通信の雛形がすぐに作れるので、まずは上の例を動かしてみましょう!
URLとURIの違いと使い分けをスパッと理解
URLとURIは似ていますが、URLは“場所を示す住所”、URIは“名前も含む住所または名前全般”と覚えるとわかりやすいです。
URI(Uniform Resource Identifier)はリソースを一意に識別する文字列の総称。URL(Uniform Resource Locator)はURIの一種で、ネット上のリソースへのアクセス方法(例:https://example.com)を示します。つまり、すべてのURLはURIですが、すべてのURIがURLではありません。
import java.net.URI;
import java.net.URL;
// URIを作成(スキームやパスなどリソース識別全般)
URI uri = new URI("urn:isbn:978-4798153146");
System.out.println(uri.getScheme()); // → urn
// URLを作成(アクセス可能な場所)
URL url = new URL("https://example.com/index.html");
System.out.println(url.getProtocol()); // → https
System.out.println(url.getHost()); // → example.com
URN(Uniform Resource Name)もURIの一種ですが、アクセス方法は含まず名前のみを表します。
とにかく「アクセスできるかどうか」を含めて書くのがURL、「何者かを識別する」のがURIと覚えれば、使い分けがグッと楽になります!
HttpURLConnectionでHTTPリクエスト/レスポンス自前処理
Java標準の HttpURLConnection
クラスを使えば、外部サーバーへのGET/POSTリクエストを自分で組み立てて送信し、レスポンスを受け取れます。
ライブラリに頼らずに動作原理を理解することは、問題発生時の原因特定に役立ちます。また軽量なコードで、依存を増やさずに済むメリットもあります。
まずは簡単なGETリクエスト例です。
import java.net.*;
import java.io.*;
URL url = new URL("https://jsonplaceholder.typicode.com/todos/1");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.setConnectTimeout(5000);
con.setReadTimeout(5000);
int status = con.getResponseCode();
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream())
);
String inputLine;
StringBuilder content = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
content.append(inputLine);
}
in.close();
con.disconnect();
System.out.println("ステータス:" + status);
System.out.println("レスポンス:" + content.toString());
POSTリクエストも同じ流れで、setDoOutput(true)
と OutputStream
へ書き込むだけです。
HttpURLConnection
を使えば、細かい設定も自前でできるので、外部API連携の基礎をしっかり押さえたいときに最適です。
タイムアウト設定&非同期通信の基本パターン
ネットワーク通信は相手が遅いとプログラムが止まってしまいます。だからタイムアウトを設定し、必要なら非同期で動かすことが大事です。
例えばサーバーからの応答が長い間帰ってこないと、画面が固まったり他の処理が進まなくなります。setConnectTimeout
と setReadTimeout
で接続や読み込みの待ち時間を制御し、非同期なら別スレッドで通信を行えば、メイン処理を止めずにすみます。
まずタイムアウト設定の例です。HTTP通信で5秒以上かかると自動で例外が投げられます。
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setConnectTimeout(5000); // 接続待ち最大5秒
con.setReadTimeout(5000); // 読み込み待ち最大5秒
次に非同期通信の基本パターン。Javaでは ExecutorService
を使って別スレッドで実行します。
import java.util.concurrent.*;
ExecutorService exec = Executors.newSingleThreadExecutor();
Future<String> future = exec.submit(() -> {
HttpURLConnection c = (HttpURLConnection) url.openConnection();
c.setConnectTimeout(3000);
c.setReadTimeout(3000);
try (BufferedReader r = new BufferedReader(
new InputStreamReader(c.getInputStream()))) {
return r.readLine();
}
});
try {
String result = future.get(4, TimeUnit.SECONDS); // 最大4秒待つ
System.out.println("結果:" + result);
} catch (TimeoutException te) {
System.out.println("通信がタイムアウトしました");
future.cancel(true);
}
exec.shutdown();
これで、メイン処理を止めずに通信し、かつ長引く場合は自動で中断できます。
タイムアウトと非同期を組み合わせれば、ユーザー体験を損なわずに安全なネット通信が実現できます!
IPv6対応とInetAddressでのホスト解決
JavaでIPv6アドレスも扱えると、最新のネットワーク環境でも問題なく動作します。InetAddress
クラスを使って、IPv4/IPv6の両方に対応しましょう。
近年はIPv4の枯渇により、IPv6が普及しています。従来のIPv4アドレス(例: 192.168.0.1)のほか、IPv6アドレス(例: 2001:db8::1)でも名前解決や接続が行えるように実装しておくことが重要です。
以下はホスト名からIPアドレスを取得し、IPv6にも対応する例です。
import java.net.*;
public class ResolveHost {
public static void main(String[] args) throws Exception {
String host = "example.com";
InetAddress[] addrs = InetAddress.getAllByName(host);
for (InetAddress addr : addrs) {
System.out.println(
addr instanceof Inet6Address ? "IPv6: " : "IPv4: "
+ addr.getHostAddress()
);
}
}
}
このコードは、対象ホストの全IPアドレスを取得し、IPv4ならInet4Address
、IPv6ならInet6Address
として判別しています。
InetAddress.getAllByName()
を使えば、IPv4もIPv6もまとめて解決できます。これで最新のネット環境にも強いJavaアプリが作れます!
まとめ:Javaでネットワークを自由に操る5つの学び
本記事では、Javaでのネットワークプログラミングの基礎から応用までを、小学5年生にもわかるやさしい言葉とコード例で解説しました。
- ソケット通信の基本:ServerSocketとSocketでTCP接続を実現し、InputStream/OutputStreamでデータをやり取り
- URLとURIの違い:URIはリソースを識別、URLはアクセス方法を含むURIの一種と理解して使い分け
- HttpURLConnectionによるHTTP処理:GET/POSTリクエストを自前で構築し、レスポンスを読み込む方法
- タイムアウト&非同期通信:
setConnectTimeout
/setReadTimeout
とExecutorService
でプログラムを止めない安全設計 - IPv6対応とホスト解決:
InetAddress.getAllByName()
でIPv4/IPv6両対応のDNSルックアップを実現
これらのテクニックを組み合わせることで、Javaで本格的なネットワークアプリケーションが作れます。ぜひ実際のプロジェクトで試し、ネットワーク制御を自由自在に扱えるようになりましょう!