対象読者
- Javaでサーバ↔クライアント間の通信をどうやるか見てみたい方
- BufferReaderやStreamReaderについて何となくの理解をしている方
- Javaを学び始めた初心者の方
できること
- Java標準のServerSocket/Socketだけで、1行メッセージをやり取りするミニサーバ・クライアントを作る
- InputStream→InputStreamReader→BufferedReaderのラップ構造を理解し、BufferdReaderインスタンス.readLine()で行単位の受信ができるようになる
- OutputStream→PrintWriterでprintln()送信&オートフラッシュの挙動を押さえる
全体の動作イメージ
- サーバが指定ポートで待機(例: 8080)。
- クライアントが接続し、1行メッセージを送信。
- サーバは受け取った行を大文字化して返信。
- 双方ともソケットを閉じて終了。
コード実装例
Server.java
// サーバ(Server.java)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class Server {
public static void main(String[] args) {
int port = 8080; // テスト用途。80は管理者権限が必要なことが多い
try (ServerSocket serverSocket = new ServerSocket(port)) {
System.out.println("サーバ起動: port=" + port);
while (true) {
try (Socket socket = serverSocket.accept();
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {
System.out.println("クライアント接続: " + socket.getInetAddress());
String line = in.readLine(); // 1行受信(改行は除去)。切断ならnull
System.out.println("受信: " + line);
if (line != null) {
out.println("サーバからの応答: " + line.toUpperCase());
}
} catch (IOException e) {
// 個別接続の例外はログに流してループ継続
e.printStackTrace();
}
}
} catch (IOException e) {
// サーバソケット生成やbind失敗
e.printStackTrace();
}
}
}
Client.java
// クライアント(Client.java)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class Client {
public static void main(String[] args) {
String host = "localhost";
int port = 8080;
try (Socket socket = new Socket(host, port);
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {
String message = "hello, socket!";
System.out.println("送信: " + message);
out.println(message); // 改行付きで送信(printlnなのでオートフラッシュで即送出)
String response = in.readLine(); // 1行受信
System.out.println("受信: " + response);
} catch (IOException e) {
e.printStackTrace();
}
}
}
細かい部分の説明(行ごとに噛み砕く)
受信側(サーバ/クライアント共通)
inと命名しているBufferdReaderインスタンスの深掘りです
- socket.getInputStream()
- ソケットの「生のバイト受信口」を取る
- まだ文字ではなくバイト列でデータを受け取ります
- new InputStreamReader(..., StandardCharsets.UTF_8)
- バイト列をUTF-8で「文字」にデコードするフィルター
- ここで初めて文字化します
- new BufferedReader(...)
- まとめ読み+内部バッファを持ち、改行を探してreadLine()(受け取った文字列を一行ずつ読むためのメソッド)を使えるようにするラッパー
- バッファとは「届いたデータを一時的に溜めるメモリ領域」。改行が来るまで貯め、見つかったら1行として返す
送信側
outと命名しているPrintWriterインスタンスの深掘りです
- socket.getOutputStream()
- ソケットの「生のバイト列送信口」
- new PrintWriter(..., true)
- 文字列を書き込むラッパー
- 第2引数trueでオートフラッシュON
- printlnを呼ぶたびにバッファが即フラッシュされ、ネットワークに流れる。
- println("...")は末尾に改行を付けて送るので、行単位でのやり取りに便利。
メインの流れ(サーバ側)
- ServerSocket serverSocket = new ServerSocket(port);
- ポートにbindして待機。
- Socket socket = serverSocket.accept();
- クライアントからの接続を受け入れ、個別のソケットを取得。
- 入出力ストリームをラップして、in.readLine()で1行受信、out.println(...)で1行応答。
- try-with-resourcesでSocket/Reader/Writerを自動クローズ。