ネットサーバー

  1. ネットサーバー
    ネット-サーバーとしてクライアントからの接続要求に応え、クライアントからのメッセージをファイルを保存する簡単なサーバーを紹介します。

  2. サーバーの処理

    1. サーバーソケット
       サーバーは ServerSocketクラスを利用し、クライアントからの接続を待ち受けます。サーバーソケットを作成するには、ポート番号を指定します。ここでは、8005 を設定します。この番号は、クライアントが接続するときのポート番号と同一にする必要があります。
       クライアントのIP番号は、クライアントの接続時に取得できます。
        ServerSocket serversocket; 
       serversocket = new ServerSocket(8005);
        System.out.println("socket=" + serversocket);

    2. クライアントへの応答
       serversocket の accept() メソッドで、クライアントからの接続要求(conect)を待ちます。accept() は接続を受けると、クライアントとのメッセージ交換を行うソケット:socket を返します。このsocketから、入力用ストリームクラス:inputstream を、さらに、行単位の入力を行うために、BufferedReader クラスのオブジェクト:netinput を作成します。
        Socket socket;
        socket = serversocket.accept();
        InputStream inputstream = socket.getInputStream();
        netinput =new BufferedReader(new InputStreamReader(inputstream));
      このnetinputより、
       String data = netinput.readLine();
      で、クライアントからのメッセージを読み出すことができます。

    3. ファイルへの記録
       ここでは、掲示板の機能を行うサーバーの原型を考えています。掲示板では、新規の到着メッセージをファイルの先頭に書き出す必要があります。記録するときは最新の記事を最後とし、逆順に表示する方法もありますが、これでは、クライアント側に負担がかかります。
       しかし、ファイルの先頭に書き出すことができるクラスは用意されていません。そこで、別の作業ファイル:temp.txt を作成し、ここに、まず到着したメッセージを書き込み、次に、受信済みのファイル message.txt を書き出します。
       最後に、message.txt を削除したのち、temp.txt ファイルを messsage.txt ファイルに名前を変更します。
       ファイルの削除や名前の変更には File クラスを利用します。

    4. 通信プロトコル
       クライアントとサーバーで交換するメッセージの方式を定めた規約を プロトコル といいます。クライアントは複数の行を送ることができますが、最後に .end の行を送り、行の最後とします。
       また、.exit の行を送ると、サーバーは実行を終了します。この、.exit は特殊な機能で、公開する機能ではありません。

    5. サーバースレッド
       サーバーは通常、serversocket.accept(); でクライアントからの接続待ちの状態です。この、状態ではサーバーは「死んだ」状態で、一切の実行ができません。したがって、サーバーにウインドウを作成し、ボタンやマウスなどのイベント処理をプログラムしても、有効ではありません。
       有効にするには、serversocket.accept(); を別のスレッドで実行し、main() のスレッドとは別に実行することが必要です。
       
  3. プログラム構成

    1. netServerクラス
      1. mainメソッド
         自身のnetServerクラスのオブジェクト:objを作成し、obj.rcvProcess() を実行します。
         
      2. rcvProcess()メソッド
         このプログラムは、try .. catch() の構文を含むため、少し複雑なブロック構造となります。まず、ソケットを利用する部分が ソケットエラーを抽出するため、try .. catch() のブロックに入ります。さらに、内部でファイルを処理する部分がまた、try .. catch() のブロックに組み込まれます。

         try {
             // 指定ポートでサーバソケット作成
             serversocket = new ServerSocket(8005);
             System.out.println("socket=" + serversocket);
             .....
         } catch (Exception e) {
              System.out.println("error socket: " + e);
         } 
        プログラムの制御の構造では、.exit メッセージを受け取るまで、サーバーの処理を続ける 
          while (!exitf) { }
        の繰り返しがあります。この内部に、クライアントからのメッセージ(行)を繰り返し読み取る繰り返しがあります。
         while (true) { String data = netinput.readLine(); .. }

  4. プログラム

    1. ネットサーバー

      import java.net.*; // Socket, ServerSocket
      import java.io.*; // InputStream, InputStreamReader, BufferedReader etc
      
      public class netServer {
      
          public static void main(String args[]) {
              netServer obj = new netServer();
              obj.rcvProcess();
          }
      
          void rcvProcess() {
              boolean exitf = false;
              Socket socket;
              ServerSocket serversocket;
              BufferedReader netinput = null; // ネットワーク経由入力
      
              try {
                  // 指定ポートでサーバソケット作成
                  serversocket = new ServerSocket(8005);
                  System.out.println("socket=" + serversocket);
      
                  while (!exitf) {
                      socket = serversocket.accept();
                      try {
                          // ソケットから入力ストリームを作成
                          InputStream inputstream = socket.getInputStream();
                          netinput =
                              new BufferedReader(new InputStreamReader(inputstream));
                      } catch (Exception e) { // 例外処理
                          System.out.println("accept : " + e);
                      }
      
                      try {
                          FileWriter fw = new FileWriter("temp.txt");
                          BufferedWriter bw = new BufferedWriter(fw);
                          PrintWriter pw = new PrintWriter(bw);
                          FileInputStream fis = new FileInputStream("message.txt");
                          BufferedReader br =
                              new BufferedReader(new InputStreamReader(fis));
      
                          // クライアントからのデータを書き込む
                          while (true) {
                              // クライアントからのメッセージ受信
                              String data = netinput.readLine();
                              System.out.println("data:" + data);
                              if (data.equals(".end"))
                                  break;
                              else if (data.equals(".exit")) {
                                  exitf = true;
                                  break;
                              } else {
                                  pw.println(data);
                              }
                          }
      
                          pw.flush(); // バッファ内のデータを出力
                          String line;
                          while ((line = br.readLine()) != null) { // 1行入力
                              pw.println(line);
                          }
      
                          pw.close();
                          bw.close();
                          fw.close();
                          fis.close();
                          br.close();
                          //System.out.println("end");
      
                      } catch (Exception e) {
                          System.out.println("error in save: " + e);
                      }
      
                      File f1 = new File("temp.txt");
                      File f2 = new File("message.txt");
                      f2.delete();
                      f1.renameTo(f2);
                      System.out.println("end of save:");
      
                  } //while(!exit)
              } catch (Exception e) {
                  System.out.println("error socket: " + e);
              }
              System.out.println(".exit");
          }
      }

  5. 実行
     これはアプリケーションですから、Javaコマンドで起動します。このプログラムはウインドウは生成しません。コンソール(起動ウインドウ)に経過を表示します。
     起動するとクライアントからの接続を待ち、接続すると、送られたメッセージをファイル:message.txt の先頭に追加します。クライアントはメッセージの最後に .end を自動付加します。また、クライアントが 行頭に .exit メッセージを送信すると、 サーバーは処理を終了します。


トップに戻る