Javaソケット通信の基本操作

サーバーサイド:

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();
    }
}

重要なポイント:

  1. connection.shutdownOutput()によるストリームクローズは片方向のみ。クライアント側の出力を停止してもサーバー側の出力は維持される。
  2. shutdownOutput()ではストリームのみクローズされ、ソケット接続自体は維持される。
  3. 直接inputStream.close()outputStream.close()を実行すると、関連するソケットもクローズされる。

Socketの有効性を判定する際には、nullチェックやクローズ状態だけでなく、以下の複合的な条件を評価する必要がある:

  • bound:バインド済みか
  • closed:クローズ済みか
  • connected:接続済みか
  • shutIn:入力ストリームがクローズか
  • shutOut:出力ストリームがクローズか
connection != null && connection.isBound() && !connection.isClosed() && connection.isConnected() && !connection.isInputShutdown() && !connection.isOutputShutdown()

タグ: Java socket Network-Programming server-client Stream

7月14日 02:21 投稿