package lecture.threadAndComm;

/**
 * TCP通信のサンプル:クライアント⇒サーバーの一方向通信
 * サーバー側とクライアント側
 * 両方ともlocalhostで実行する前提
 *
 * サーバー
 * 3000 ポートで待ち受ける -- acceptメソッドを呼び出す
 * クライアントから接続が来てacceptが成立したらSocketが戻される
 * スレッドを生成して戻されたSocketを渡し、スレッドでクライアントと通信
 * メインスレッドは他のクライアントの接続を待ち受けるため、再びacceptする
*/

import java.net.*;

import lecture.common.Log;
import lecture.common.Util;

import java.io.*;


/** サーバーのサンプル */
class SimpleCommServer {
  public static int PORT_NO = 3000;
  public static String END = "end";
  public static void main(String[] args) throws IOException {
    ServerSocket serverSoc = null;
    try {
      serverSoc = new ServerSocket(PORT_NO);
      //
      //クライアントからの接続を待機する
      for (;;) {
        Log.print("Waiting for Connection. ");
        Socket socket = serverSoc.accept();
        Log.print("Connect to " + socket.getInetAddress());
        // 接続があった ⇒ スレッドを生成してクライアントとの通信はスレッドに任せる
        (new SimpleServerThread(socket)).start();
        // 他のクライアントからの接続を待つためにループする
      }
    }
    catch (IOException e) {
      e.printStackTrace();
    }
    finally {
      serverSoc.close();
    }
  }
}

/**
 *  サーバー用のスレッド
 *  クライアントから接続後、当該クライアントとの通信を行う
 *  本クラスは、クライアントから送られてきたメッセージを表示するのみ
 *  "end"が来た場合には、スレッドを終了する
 */
class SimpleServerThread extends Thread {
  private Socket socket;
  private BufferedReader reader;
  public SimpleServerThread(Socket socket) throws IOException {
    this.socket = socket;
    reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  }
  public void run() {
    try {
      for (;;) {
        String line = reader.readLine();
        Log.print("Message from client :" + line);
        if ((line == null) || line.equals(SimpleCommServer.END)) {
          break;
        }
      }
      Log.print("server thread ended");
    }
    catch(IOException ex) {
      ex.printStackTrace();
    }
    finally {
      try {
        reader.close();
        socket.close();
      }
      catch(Exception ex) {
        // 無視
      }
    }
  }
}

/**
 * クライアントのサンプル
 * サーバーに接続する
 * 接続後、messagesに入ったメッセージをサーバーに送信.
 */
class SimpleCommClient {
private static String[] messages = { "aaa","bbb","ccc","ddd",SimpleCommServer.END };
  public static void main(String[] args) throws IOException {
    Socket socket = null;
    PrintWriter writer = null;
    try {
      //
      // 何からの手段で取得したIP(ホスト名)とポート番号を設定する
      // サンプルなので、適当に設定している
      socket = new Socket();
      InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1",SimpleCommServer.PORT_NO);
      socket.connect(socketAddress, 10000);
      //
      //接続先の情報を入れるInetAddress型のinadrを用意する。
      InetAddress inadr;
      //inadrにソケットの接続先アドレスを入れ、nullである場合には接続失敗と判断する。
      //nullでなければ、接続確立している。
      if ((inadr = socket.getInetAddress()) != null) {
        Log.print("Connect to " + inadr);
      }
      else {
        Log.print("Connection failed.");
        System.exit(1);
      }
      writer = new PrintWriter(socket.getOutputStream());
      // メッセージを送信する
      for ( int i=0; i<messages.length; i++) {
        String message = messages[i];
        writer.println(message);
        Log.print("Send message: " + message);
        Util.sleep(1000);
      }
    }
    catch (IOException e) {
        e.printStackTrace();
    }
    finally {
      if (writer != null) {
        writer.close();
      }
      if (socket != null) {
        socket.close();
      }
    }
  }
}
//---------------------------------------------------
//・目次 - スレッドと通信
//  http://blogs.yahoo.co.jp/artery2020/40575722.html
//・目次 - Java入門
//  http://blogs.yahoo.co.jp/artery2020/39975776.html
//・目次 - ビジネスパーソンの常識と非常識
//  http://blogs.yahoo.co.jp/artery2020/39728331.html
//・目次 - 論理・発想・思考についての考察と鍛え方
//  http://blogs.yahoo.co.jp/artery2020/39657784.html
//---------------------------------------------------