JavaでSocketクライアントを実装しレスポンスを取得する方法

Javaの標準APIを使用して、TCPソケット経由でサーバーにリクエストを送信し、その応答データを取得する実装例を紹介します。コードは自己完結型で、初心者でも理解しやすいように設計されています。

Socketクライアントユーティリティクラス

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.*;

public class TcpSocketClient {

    private static final Logger logger = LoggerFactory.getLogger(TcpSocketClient.class);

    private static final String INVALID_ADDRESS = "ホストまたはポートが無効です: %s:%d";
    private static final String NO_RESPONSE = "サーバーから応答がありません: %s:%d";
    private static final String CONNECTION_FAILED = "接続に失敗しました。サーバーが稼働中か確認してください: %s:%d";
    private static final String REQUEST_TIMEOUT = "リクエストがタイムアウトしました: %s:%d";
    private static final String IO_ERROR = "I/Oエラーが発生しました: %s:%d";

    public static SocketResult send(String host, int port) {
        return send(host, port, null);
    }

    public static SocketResult send(String host, int port, byte[] payload) {
        SocketResult result = new SocketResult();
        result.setRequestData(payload);

        if (StringUtils.isBlank(host) || port <= 0) {
            result.setErrorMessage(String.format(INVALID_ADDRESS, host, port));
            return result;
        }

        try (Socket socket = new Socket()) {
            socket.connect(new InetSocketAddress(host, port), 5000);
            socket.setSoTimeout(60000);

            try (OutputStream out = socket.getOutputStream();
                 InputStream in = socket.getInputStream()) {

                if (payload != null && payload.length > 0) {
                    out.write(payload);
                    out.flush();
                }
                socket.shutdownOutput();

                result.setSent(true);

                if (in != null) {
                    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
                    byte[] readBuffer = new byte[1024];
                    int bytesRead;
                    while ((bytesRead = in.read(readBuffer)) != -1) {
                        buffer.write(readBuffer, 0, bytesRead);
                    }
                    result.setResponseData(buffer.toByteArray());
                } else {
                    result.setErrorMessage(String.format(NO_RESPONSE, host, port));
                }
            }
        } catch (ConnectException e) {
            result.setErrorMessage(String.format(CONNECTION_FAILED, host, port));
            logger.error(result.getErrorMessage(), e);
        } catch (SocketTimeoutException e) {
            result.setSent(true);
            result.setErrorMessage(String.format(REQUEST_TIMEOUT, host, port));
            logger.error(result.getErrorMessage());
        } catch (IOException e) {
            result.setSent(true);
            result.setErrorMessage(String.format(IO_ERROR, host, port));
            logger.error(result.getErrorMessage(), e);
        }

        return result;
    }
}

レスポンス結果を格納するDTOクラス

import java.io.Serializable;

public class SocketResult implements Serializable {

    private static final long serialVersionUID = 1L;

    private byte[] requestData;
    private byte[] responseData;
    private String errorMessage;
    private boolean sent = false;

    // Getters and Setters
    public byte[] getRequestData() { return requestData; }
    public void setRequestData(byte[] requestData) { this.requestData = requestData; }

    public byte[] getResponseData() { return responseData; }
    public void setResponseData(byte[] responseData) { this.responseData = responseData; }

    public String getErrorMessage() { return errorMessage; }
    public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; }

    public boolean isSent() { return sent; }
    public void setSent(boolean sent) { this.sent = sent; }
}

テスト用の簡易サーバー実装

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class MockSocketServer {
    public static void main(String[] args) throws IOException {
        try (ServerSocket server = new ServerSocket(15999)) {
            System.out.println("サーバー起動: ポート15999で待機中...");
            while (true) {
                try (Socket client = server.accept();
                     InputStream input = client.getInputStream();
                     OutputStream output = client.getOutputStream()) {

                    System.out.println("クライアント接続を受信");

                    ByteArrayOutputStream received = new ByteArrayOutputStream();
                    byte[] buffer = new byte[1024];
                    int len;
                    while ((len = input.read(buffer)) != -1) {
                        received.write(buffer, 0, len);
                    }

                    String requestText = new String(received.toByteArray(), "UTF-8");
                    System.out.println("受信メッセージ: " + requestText);

                    output.write("サーバーからの応答データ".getBytes("UTF-8"));
                    output.flush();
                }
            }
        }
    }
}

クライアント側のテストコード

public class SocketClientTest {
    public static void main(String[] args) {
        SocketResult result = TcpSocketClient.send("127.0.0.1", 15999, "クライアントからのリクエスト".getBytes());

        if (result.getErrorMessage() != null) {
            System.err.println("エラー: " + result.getErrorMessage());
        } else {
            System.out.println("受信応答: " + new String(result.getResponseData()));
        }
    }
}

上記のサーバーを先に起動し、その後クライアントを実行すると、双方向の通信が確認できます。タイムアウトや接続エラーなどの例外ケースも適切にハンドリングされています。

タグ: Java socket TCP

6月1日 17:12 投稿