サーバーサイド:
public class SocketServer {
public static void main(String[] args) throws Exception {
// サーバーソケットを作成し、指定ポートで待受開始
ServerSocket serverSocket = new ServerSocket(8765);
// クライアントからの接続を待機
Socket clientConnection = serverSocket.accept();
// 入力ストリームを取得してクライアントデータを読み込み
InputStream inputStream = clientConnection.getInputStream();
InputStreamReader streamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(streamReader);
String receivedData = null;
// クライアントからデータが送信されるまでブロック
while ((receivedData = bufferedReader.readLine()) != null) {
System.out.println("サーバー受信: " + receivedData);
}
clientConnection.shutdownInput(); // 入力ストリームのみをクローズ
// 出力ストリームを取得し、クライアントへ応答
OutputStream outputStream = clientConnection.getOutputStream();
PrintWriter writer = new PrintWriter(outputStream);
writer.write("接続確認完了");
writer.flush();
// リソースを解放(クライアントへデータ送信)
writer.close();
outputStream.close(); // ソケットもクローズ
bufferedReader.close();
streamReader.close();
inputStream.close();
clientConnection.close();
serverSocket.close();
}
}
クライアントサイド:
public class SocketClient {
public static void main(String[] args) throws Exception {
// サーバーに接続するクライアントソケットを作成
Socket connection = new Socket("127.0.0.1", 8765);
// サーバーへデータ送信のための出力ストリームを取得
OutputStream output = connection.getOutputStream();
PrintWriter printWriter = new PrintWriter(output);
printWriter.write("認証情報: user=test; pass=secret");
printWriter.flush();
connection.shutdownOutput(); // 出力ストリームをクローズ(サーバーへデータ送信、ソケットは維持)
// サーバーからの応答を受信する入力ストリームを取得
InputStream input = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
String response = null;
// サーバーからデータが届くまでブロック
while ((response = reader.readLine()) != null) {
System.out.println("クライアント受信: " + response);
}
// すべてのリソースをクローズ
reader.close();
input.close();
printWriter.close();
output.close(); // ソケットもクローズ
connection.close();
}
}
重要なポイント:
connection.shutdownOutput()によるストリームクローズは片方向のみ。クライアント側の出力を停止してもサーバー側の出力は維持される。shutdownOutput()ではストリームのみクローズされ、ソケット接続自体は維持される。- 直接
inputStream.close()やoutputStream.close()を実行すると、関連するソケットもクローズされる。
Socketの有効性を判定する際には、nullチェックやクローズ状態だけでなく、以下の複合的な条件を評価する必要がある:
- bound:バインド済みか
- closed:クローズ済みか
- connected:接続済みか
- shutIn:入力ストリームがクローズか
- shutOut:出力ストリームがクローズか
connection != null && connection.isBound() && !connection.isClosed() && connection.isConnected() && !connection.isInputShutdown() && !connection.isOutputShutdown()