Java Socket 〜極小サーバーで通信の基本を学ぶ〜

java.net.ServerSocket

このクラスを使用してサーバーを作成します。
サーバー側のコードは以下の通りになります。
ちなみに通信がまともに繋がるまで、テストした時の残骸が残っております。

サーバー

/**
 * サーバーソケットクラス。
 * コンストラクタで指定されたポート番号でサーバーを起動します。<br/>
 * ローカルホスト(アプリを起動するPC)上の指定ポート番号で受付を開始します。
 * @author takunoji
 * 2019/07/20
 */
public class SocketServerBasic {
    private ServerSocket server;
    /**
     * コンストラクタ。
     * 
     * @param portNo アクセスを受け付けるポート番号
     */
    public SocketServerBasic(int portNo) {
        try {
            server = new ServerSocket(portNo);
            if (server.isBound() == false) {
                server.bind(new InetSocketAddress("localhost", portNo));
                server.setSoTimeout(3000);
            }
        } catch (IOException e) {
            this.finalize();
            e.printStackTrace();
        }
    }

    /**
     * Objectクラスの終了処理(ガベージコレクションに呼ばれる)
     */
    @Override
    public void finalize() {
        // メモリの解放
        server = null;
    }

    /**
     * コンストラクタで作成されたサーバーソケットで
     * 受付処理を開始する。
     */
    public void startServer() {
        try {
            System.out.println("*** SocketServer start " + server.isBound() + "***");
            Socket recieve = server.accept();
            System.out.println("*** Server Get Request start***");
            // 受信データの読み込み
            StringBuilder responseTxt = new StringBuilder("<Response>");
            // 受信状態
            System.out.println("クライアント: " + recieve.getRemoteSocketAddress());
            System.out.println("接続: " + recieve.isConnected());
            System.out.println("入力ストリームが閉じている: " + recieve.isInputShutdown());

            // 受信したリクエスト
            InputStream in = recieve.getInputStream();
            // 返却するレスポンス
            OutputStream writer = recieve.getOutputStream();
            System.out.print("Server recieve is ...");
            int c = 0;
            // CRとCRLFの場合で入力が終了している時がある
            while((c = in.read()) != -1) {
                char ch = (char)c;
                responseTxt.append(ch);
                // 空の場合
                if (c == 10 || c == 13) {
                    break;
                }
            }
            System.out.println(responseTxt.toString());
            System.out.println("*** Server Send Response start***");
            // レスポンス送信
            writer.write((responseTxt.toString() + System.getProperty("file.separator")).getBytes());
            writer.flush();
            in.close();
            writer.close();
            System.out.println("*** SocketServer end ***");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 開いたストリームを閉じる
            try {
                closeServer();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * ソケットサーバーを終了します。
     */
    public void closeServer() throws IOException {
        server.close();
        server = null;
    }

    /**
     * メインメソッド
     * @param args プログラム引数
     */
    public static void main(String[] args) {
        SocketServerBasic serverSocket = new SocketServerBasic(8080);
        serverSocket.startServer();
    }
}

クライアント

public class ClientSocketBasic {
    private static final String HOST = "localhost";
    private static final int PORT = 8080;
    /**
     * コンストラクタ
     * @param portNo ポート番号
     */
    public static void main(String[] args) {
        System.out.println("*** SocketClient start ***");
        try (Socket sock = new Socket(HOST, PORT)) {
            // 受信したレスポンス
            InputStream reader = sock.getInputStream();
            // 送信するリクエスト
            OutputStream writer = sock.getOutputStream();
            System.out.println("接続済み: " + sock.isConnected());
            System.out.println("接続サーバー: " + sock.getRemoteSocketAddress());
            // リクエスト送信
            writer.write("ping...\n".getBytes());
            writer.flush();

            System.out.println("*** Testing start " + sock.getInetAddress() + " ***");
            // レスポンス受信
            int c = 0;
            while((c = reader.read()) != -1) {
                System.out.print((char)c);
            }
            System.out.println("*** Testing end***");

            // 終了処理
            reader.close();
            writer.close();
            sock.close();
            System.out.println("*** SocketClient end ***");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

ハマったところ

ここで自分が詰まったのはクライアントからのデータを受信するときに「BufferedReader#readLine()]」を使用していたところです。

原因は。。。

データを送信するときに改行がないと受信時にデータの終わりが確認できないので「readLine()」のところで処理が止まってしまうところです。
とりあえずはこちらを参照して実装しました。
実装してみたところ、サーバーとクライアントの送受信で互いに「読み取り」処理の時の区切りが悪かった。。。なので下のように、送信データの終わりが明確にわかるように実装しました。

int c = -;
while((c = reader.read()) != -1) {
   char ch = (char) c;
   stBuilder.append(ch);
}

こんな感じで実装していたのですが、読み取るデータがいつになっても「-1」にならない事件が起きてしまい。。。
結局は下のようにコードを直しました。

int c = -;
while((c = reader.read()) != -1) {
   char ch = (char) c;
   stBuilder.append(ch);
   if(c == 10 || c == 13) {
       break;
   }
}

c == 10, 13の部分はchar型のint値です。10はLF(改行文字)で13はCR('改行文字)のようです。参考サイト
ソースコードはGitにアップしています。SocketServerBasic.java, ClientSocketBasic.javaをアップしてあります。

ネットワーク確認コマンド

コマンドプロンプトで下のようなコマンドを叩くと、使用しているポートがわかります。以下コマンドの書き方

netstat -nao | find "[ポート番号]"
netstat -a(使用している全ポートを一覧)

勘違いによるエラー

1.接続ポートを間違える

あたりまえだけど、サーバーがlocalhost: 2000で動いているならば、クライアントはlocalhost: 2000に接続する必要があります。「java.net.ConnectException」が出力されます。

2.テストしたときのコネクションが残っている

実装時に処理の起動確認を行いながらやりますが、処理の実行時にコネクションが消えていない、となると「Address already in use」とかエラーが出ます。

3.クライアントからの送信するデータの終わり

クライアントからサーバーへデータを送信するデータの終わりを示す文字として「改行コード」を入れてやる必要がある。でないといつまでもサーバーが受信待機する。

とりあえず完了

いやー、read()処理の部分でハマりました(笑)
昔はreadLine()とかで問題なく動いたのですが、ちょっと変わっているようです。今回の実装はJDK1.8での実装になります。
でわでわ。。。

やったこと一覧

  1. Eclipse+Gluonでスマホアプリを作る
  2. Micro:bitで遊ぶ
  3. Eclipseのセットアップ: 再生リスト
  4. LWJGLGitBook Chapter1-7
  5. IntelliJ IDEA〜セットアップなど〜
  6. Java Coord〜Java + Discord〜
  7. Java Basic〜Javaの基本〜: 再生リスト
  8. JavaDocJavaDocの解釈〜
  9. ラズパイ(RPi)関連〜RPiで遊んでみる〜
  10. JavaミニGame〜Java Console Game〜
  11. Eclipseアプリ作成〜家計簿アプリ作成〜
  12. OpenCv〜環境構築〜
  13. OoenCV + JavaFX
  14. JavaFXでハローワールド〜OpenCVチュートリアル迄〜
  15. Git操作〜Git関連〜
  16. JUnitJavaで遊ぶならこれ!〜
  17. TensorFlow〜Kerasで機械学習〜

ワンポイントレッスン的な

  1. JavaFX SceneBuilder〜ボタンにメソッドを割り当てるワンポイント〜
  2. JavaFX LineChart 〜グラフを描く、ワンポイントレッスン的な〜
  3. ND4J ベクトル生成〜ワンポイントレッスン的な〜

Micro:bitで遊ぶ

  1. Micro:bit(Chibi:bit) での開発環境セットアップ
  2. Micro:bit スマホでプログラミング〜ブラウザにアクセス〜
  3. Micro:bit スマホでプログラミング〜Bluetoothの設定〜
  4. PHP JS 〜WebSocketもどきの作成〜
  5. PHP ServerSocket 〜レンタルサーバーでSocket受信〜
  6. Python websocket client〜WebSocket送信処理を作る〜
  7. Micro:bit Python 〜マイクロビット→PCへシリアル通信〜
  8. ターミナル(コマンド)を使う 〜FTPSを使ってファイルアップロード〜
  9. Microbit リファレンス 〜サイトを眺めてみる〜
  10. Microbitで遊んでみる
  11. Microbitで遊ぶ〜ボタンを押す〜
  12. Microbitで遊ぶ〜シリアル通信をする〜
  13. Java Microbit Serial data connect 〜シリアル通信〜※中途半端です
  14. Microbit Python 〜シリアル通信データを受け取る〜
  15. Microbit Python HTTP リクエストを飛ばす
  16. Microbit花火〜MicrobitからWebServerまでの旅〜

Eclipse セットアップ

  1. Java Install Eclipse〜開発ツールのインストール〜
  2. TensorFlow C++環境〜EclipseCDTをインストール〜
  3. Setup OpenGL with JavaJOGLを使う準備 for Eclipse
  4. Eclipse Meven 開発手順〜プロジェクトの作成〜
  5. Java OpenCV 環境セットアップ(on Mac)
  6. Eclipse SceneBuilderを追加する
  7. JavaFX SceneBuilder EclipseSceneBuilder連携~

Eclipse+Gluon(MobileApp)

  1. Eclipse Android〜Gluonでアプリを作る〜
  2. Eclipse Android〜Gluonでアプリを作る2〜
  3. Eclipse Android〜Gluonでアプリを作る3: 3Dモデル〜
  4. Eclipse Android〜Gluonでアプリを作る4: 普通に作る〜
  5. Eclipse Android〜Gluonでアプリを作る5: ゲーム部分を作る〜

LWJGL

  1.  Chapter1[外枠の表示のみ]
  2. Chapter2-1〜クラスの構成〜
  3. Chapter2-2〜インターフェースの使い方と詳細〜
  4. Chapter2-3〜GameEngineクラス(サンプルクラス)〜/li>
  5. Chapter2-4〜Windowクラス(サンプルクラス)〜
  6. Chapter3〜描画処理を読む〜
  7. Chapter4〜シェーダについて〜
  8. Chapter5-1〜レンダリングについて〜
  9. Chapter5-2〜レンダリング詳細〜
  10. Chapter6Projection(投影)
  11. Chapter7-1〜Cubeを作る〜
  12. Chapter7-2〜Texture〜
  13. Java 3DGame LWJGL Retry Lv1 〜動かして理解する〜
  14. Java 3DGame LWJGL Retry Lv2 〜動かして理解する2
  15. Java 3DGame LWJGL Retry Lv3 Texture〜動かして理解する3「負け越し」
  16. Java 3DGame LWJGL Retry Lv4 デバック〜動かして理解する4「黒星」
  17. Java 3DGame LWJGL Retry Lv5 遊んでみる〜動かして理解する5「引分け」
  18. Java 3DGame LWJGL Retry Lv6 遊んでみる2〜動かして理解する6「白星」
  19. ava 3DGame LWJGL Retry Lv7 遊んでみる3〜全部テクスチャにする〜

IntelliJ IDEA

  1. IntelliJ IDEA 環境構築 〜インストールと起動〜
  2. IntelliJ IDEA GitGitリポジトリからクローン〜
  3. IntelliJ IDEA 使い方〜Git接続 Java起動 etc
  4. IntelliJ IDEA Jarファイルを作る
  5. IntelliJ IDEA 使い方〜Maven Projectの作成〜
  6. IntelliJ IDEA 使い方〜Mavenでライブラリを追加する〜
  7. IntelliJ IDEA 使い方〜Javaのコンパイルレベル設定〜
  8. IntelliJ IDEA Gradleセットアップ〜コマンド入力部の表示〜
  9. IntelliJ IDEA Discord Botを作る〜Gradle環境のセットアップ〜

Java Discord

  1. IntelliJ IDEA Discord Botを作る〜Gradle環境のセットアップ〜
  2. Java Discord セットアップ〜Hello Discord
  3.  Java Discord ピンポン〜Discordプログラム〜
  4. Java Discord Listener実装〜コマンドを好きなだけ追加しよう〜

Java Basic

  1. Java Basic Level 1 Hello Java
  2. Java Basic Level2 Arithmetic Calculate
  3. Java Basic Level3 About String class
  4. Java Basic Level 4Boolean
  5. Java Basic Level 5If Statement
  6. Java Basic Summary from Level1 to 5
  7. Java Basic Level 6 Traning of If statement
  8. Java Basic Level8 How to use for statement
  9. Java Basic Level 8.5 Array
  10. Java Basic Level 9Training of for statement
  11. Java Basic Level 10 While statement
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2
  14. サンプル実装〜コンソールゲーム〜
  15. Java Basic インターフェース・抽象クラスの作り方
  16. Java Basic クラスとは〜Step2_1
  17. Java Basic JUnit 〜テストスイートの作り方〜

JavaDoc

  1. Java Doc 読解 System
  2. Java Doc 読解〜System.out
  3. Java Doc読解 System.In
  4. JavaDoc 読解 Filesクラス
  5. Java Doc読解 BufferedReader
  6. Java Doc 読解〜BufferedWriter
  7. Java Doc 読解 List JavaDocList その1〜
  8. Java Doc 読解 Map
  9. Java Doc Classloader

ラズパイ(RPi)関連

  1. ラズパイ SSH接続メモ
  2.  ラズパイ Under-voltage detected! 〜エラー対処〜
  3.  ラズパイ(CUI)セットアップ
  4.  RPi Settingup Wifi in CUI ~ラズパイ CUI Wifi接続~
  5. Memos about Settingup RPi ~使用したコマンドメモ~
  6. RPi and JavaFX sample of deployment 〜ラズパイにサンプルデプロイ〜
  7.  RPi JavaFX execution ~ラズパイ JavaFX自動起動~
  8. RPi Install Git 〜ラズパイにGitのインストール〜
  9. RPi Java Swing〜ラズパイにJava Swingアプリを起動する〜※失敗しています。。。」
  10. RPi Maven Install 〜ラズパイでMeven
  11. Install XFCE4 on RPi 〜ラズパイに高速軽量デスクトップインストール〜

<Java Step1〜ミニゲーム作成>

  1. Java Hello World はじめのプログラム Step1-1
  2. Java 四則演算 演算子 Step1-2
  3. Java データ型 変数の扱い方〜Step1-2-1
  4. Java Basic Booleanなどの意味 Step1_2_2
  5. Java Basic for Step1_3_1
  6. Java Basic While Step1_3_2
  7. Java Basic try catch Step1_3_3
  8. Java Basic クラスとは〜Step2_1
  9. Java Basic API Listの使い方 Step2_2
  10. Java Basic インターフェース Step2_3
  11. Java Basic ミニゲーム作成 Step3_1
  12. Java Basic ミニゲーム作成 Step3_2

 家計簿アプリ作成

  1. Eclipse アプリ作成 Lv1〜家計簿を作る準備〜
  2. Eclipse アプリ作成 Lv2〜家計簿を作る土台作り〜
  3. Eclipse アプリ作成 Lv33Dグラフ用Cube作り〜
  4. Eclipse アプリ作成 Lv43Dグラフ用Cubeに高さを与える〜
  5. Eclipse アプリ作成 Lv5〜惨敗:CubeTextureを貼る〜
  6. Eclipse アプリ作成 Lv7Cubeを日付順に並べる〜

Git

  1. Java Git clone in Eclipse 〜サンプルの取得〜
  2. Eclipse Gitリポジトリの取得 GitからソースをPullしよう〜
  3. IntelliJ IDEA GitGitリポジトリからクローン〜

OpenCv

  1. Java OpenCV 環境セットアップ(on Mac)
  2. Java OpenCv Lv1 〜入門: 写真の表示〜
  3. Java OpenCV Lv2 〜画像を表示する〜
  4. Java OpenCV Lv3 〜画像の平滑化(smooth())
  5. Java OpenCV Lv3 〜画像にガウシアンフィルタ(GaussianBlur())
  6. Java OpenCV Lv3 〜画像に中央値フィルタ(medianBlur())
  7. Java OpenCV Lv4 〜画像の中身をみてみる〜
  8. Java OpenCV Lv5 Matクラスで描画処理〜
  9. Java OpenCV Lv6 Matクラスで背景から作成してみる〜
  10. Java OpenCV Lv7 MatクラスでEllipseしてみる〜
  11. Java OpenCV Lv9 〜画像編集「足し算」(cvAdd)
  12. Java OpenCV Lv9 〜画像編集「引き算」(cvSubtract)
  13. Java OpenCV Lv9 〜画像の掛け算〜
  14. Java OpenCV Lv10 〜行列演算Mat#submat()
  15. Java OpenCv Lv10〜画像の平均値をだす〜

OpenCv + JavaFX

  1. EclipseにSceneBuilderを追加する
  2. JavaFX SceneBuilder 〜EclipseとSceneBuilder連携~
  3. Java OpenCv Lv1 〜入門: 写真の表示〜
  4. Java OpenCV Lv2 〜JavaFXでの画像表示〜
  5. Java OpenCv ビデオキャプチャ〜カメラからの入力を表示〜
  6. OpenCV tutorial〜ヒストグラム〜
  7. OpenCV tutorial 解析 〜ヒストグラム〜
  8. OpenCV tutorial 解析2 〜ヒストグラム計算〜
  9. OpenCV tutorial 〜フーリエ変換など〜

JavaFXでハローワールド〜OpenCVまで

  1. Java 初めてでも大丈夫〜ステップアッププログラミングのススメ〜
  2. ステップアッププログラミング〜Java FxでHelloWorld解説〜
  3. Java StepUpPrograming〜JavaFX で四則計算〜
  4. Java StepUpPrograming〜JavaFXで画面切り替えを作る1〜
  5. Java StepUpPrograming〜JavaFXで画面切り替え2ボタン作成〜
  6. Java StepUpPrograming〜JavaFXで画面切り替え3アクション〜
  7. Java StepUpPrograming〜JavaFXで画面切り替え4Pane切り替え〜
  8. Java StepUpPrograming〜JavaFXで画面切り替え5WebEngine〜

JavaFX + ND4Jで機械学習準備

  1. JavaFX + ND4J〜数学への挑戦1:ND4Jのインストール〜
  2. JavaFX + ND4J〜数学への挑戦2: 行列の計算〜
  3. Java + ND4J 〜数学への挑戦3: ベクトル(配列)の作成方法〜
  4. ND4J ベクトル生成〜ワンポイントレッスン的な〜
  5. JavaFX + ND4J 〜数学への挑戦:5グラフを描く〜
  6. JavaFX + ND4J 〜グラフ作成の準備〜
  7. JavaFX + ND4J 〜グラフ作成:とりあえず表示〜
  8. JavaFX グラフ描画〜AreaChartを使う〜
  9. JavaFX + ND4J〜数学への挑戦6:グラフの土台を作る〜

JUnit関連

  1. Java Basic JUnit 〜テストスイートの作り方〜

TensorFLowを学ぶ

  1. Tensorflow Keras 〜初めてのKeras
  2. Tensorflow Keras Errors”python is not installed as a framework.”
  3. Python Tensorflow 〜初めての人工知能(TensorFlowインストール)
  4. Tensorflow Keras〜初めのトレーニング_1
  5. Tensorflow Keras〜初めのトレーニング_2:前処理〜
  6. TensorFlow Keras〜テキストの分類〜
    1. TensorFlow Keras 実行結果〜テキストの分類〜
  7. Python TensorFlow tutorial〜チュートリアルを進めるコツ、ワンポイント〜
  8. TensorFlow Keras〜回帰、準備から予測まで〜
  9. TensorFlow Java 環境構築〜JavaでもTensorFlow〜

[rakuten ids="soukai:10640969"]

 
 



投稿者:

takunoji

音響、イベント会場設営業界からIT業界へ転身。現在はJava屋としてサラリーマンをやっている。自称ガテン系プログラマー(笑) Javaプログラミングを布教したい、ラスパイとJavaの相性が良いことに気が付く。 Spring framework, Struts, Seaser, Hibernate, Playframework, JavaEE6, JavaEE7などの現場経験あり。 SQL, VBA, PL/SQL, コマンドプロント, Shellなどもやります。

コメントを残す