【Java】 簡単なチャットツールを作成する

■ サンプル

クライアントサイド

ChatClient.java
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class ChatClient {
   // ホスト名
   private static final String HOST_NAME = "localhost";
   // ポート番号
   private static final int PORT = 12345;
   
   public static void main(String args[]) {
      try {
         // サーバと接続するためのソケットを作る
         Socket socket = new Socket(HOST_NAME, PORT);
         // ユーザからの入力のストリームの作成
         BufferedReader ui = new BufferedReader(
               new InputStreamReader(System.in));
         // サーバからの入力のストリームの作成
         BufferedReader in = new BufferedReader(new InputStreamReader(
               socket.getInputStream()));
         // サーバへの出力のストリームの作成
         PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
         // ユーザへの出力のストリームの作成
         PrintWriter uo = new PrintWriter(System.out, true);
         // ユーザ入力をサーバに転送するスレッドを作成し, start
         Sender toServer = new Sender(ui, out);
         toServer.start();
         // サーバからの入力をユーザに転送するスレッドを作成し, start
         Sender fromServer = new Sender(in, uo);
         fromServer.start();
      } catch (Exception ex) {
         ex.printStackTrace();
      }
   }
}
Sender.java
import java.io.BufferedReader;
import java.io.PrintWriter;

public class Sender extends Thread {
   // 入力ストリーム
   BufferedReader in;
   // 出力ストリーム
   PrintWriter out;

   // コンストラクタ
   public Sender(BufferedReader in, PrintWriter out) {
      this.in = in;
      this.out = out;
   }

   // スレッドが start すると、これが呼ばれ動き続ける
   public void run() {
      try {
         String inputData;
         // 入力ストリームから一行入力
         while ((inputData = this.in.readLine()) != null) {
            // 出力ストリームに一行出力
            this.out.println(inputData);
         }
      } catch (Exception ex) {
         ex.printStackTrace();
      }
   }
}

サーバサイド

ChatServer.java
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

public class ChatServer {
   // ポート番号
   private static final int PORT = 12345;
   // 各クライアントを記憶するリスト.
   List<Worker> workers;

   // コンストラクタ
   public ChatServer() {
      // リストを作成
      workers = new ArrayList<Worker>();
      Socket socket;
      try {
         // ServerSocketを作成
         ServerSocket serverSocket = new ServerSocket(PORT);

         while (true) {
            // クライアントからのアクセスをうけつけた
            socket = serverSocket.accept();
            int i = 0;
            for (Worker worker : workers) {
               i++;
               // 空いている要素があったら,
               if (worker == null) {
                  // Workerを作って
                  worker = new Worker(i, socket, this);
                  // 対応するスレッドを実行
                  worker.start();
                  break;
               }
            }
            if (i == this.workers.size()) {
               System.out.println("Can't serve");
            }
         }
      } catch (IOException ioe) {
         System.out.println(ioe);
      }
   }

   public static void main(String args[]) throws IOException {
      // インスタンスを1つだけ作る.
      new ChatServer();
   }

   public synchronized void sendAll(String inputData) {
      for (Worker worker : this.workers) {
         // workerが空でなければ文字列を送る
         if (worker != null)
            worker.send(inputData);
      }
   }

   // クライアント n が抜けたこと記録し,他のユーザに送る
   public void remove(int n) {
      this.workers.remove(n);
      this.sendAll("quiting [" + n + "]");
   }
}
Worker.java
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

// クライアントとの通信を担当するスレッド
public class Worker extends Thread {
   // 通信のためのソケット
   Socket socket;
   // そのソケットから作成した入出力用のストリーム
   PrintWriter out;
   BufferedReader in;
   // サーバ本体のメソッドを呼び出すために記憶
   ChatServer chatServer;
   // 担当するクライアントの番号
   int id;

   // コンストラクタ
   public Worker(int id, Socket socket, ChatServer chatServer) {
      this.id = id;
      this.chatServer = chatServer;
      this.socket = socket;
      this.out = null;
      this.in = null;
   }

   // 対応するスレッドが start した時に呼ばれる.
   public void run() {
      try {
         // ソケットからストリームの作成
         this.out = new PrintWriter(this.socket.getOutputStream(), true);
         this.in = new BufferedReader(new InputStreamReader(
               this.socket.getInputStream()));
         String inputData = null;
         // ソケットからの入力があったら,
         while ((inputData = this.in.readLine()) != null) {
            // クライアント全体に送る.
            this.chatServer.sendAll("[" + this.id + "]" + inputData);
         }
         // 自分自身をテーブルから取り除く
         this.chatServer.remove(this.id);
         // ソケットを閉じる
         this.socket.close();
      } catch (Exception ex) {
         ex.printStackTrace();
         this.chatServer.remove(this.id);
      }
   }

   // 対応するソケットに文字列を送る
   public void send(String inputData) {
      this.out.println(inputData);
   }
}


関連記事

Socket 通信を行う ~Server側/Client側の実装例~

http://blogs.yahoo.co.jp/dk521123/33075148.html

Java で、SSL通信を行うには

http://blogs.yahoo.co.jp/dk521123/33122920.html

SocketChannel / ServerSocketChannel ~ブロッキングモード編~

http://blogs.yahoo.co.jp/dk521123/35067257.html

SocketChannel / ServerSocketChannel ~ノンブロッキングモード編~

http://blogs.yahoo.co.jp/dk521123/35120798.html

ノンブロッキングチャネル の SSL接続

http://blogs.yahoo.co.jp/dk521123/35077762.html