DrawServerTcp.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | package jp.ac.utsunomiya_u.is; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Scanner; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.logging.Level; import java.util.logging.Logger; public class DrawServerTcp { // DrawTaskのリスト private final ArrayList<DrawTask> drawTasks = new ArrayList<>(); public static void main(String[] args) { DrawServerTcp drawServer = new DrawServerTcp(); } public DrawServerTcp() { // Scannerクラスのインスタンス(標準入力System.inからの入力) try (Scanner scanner = new Scanner(System.in)) { System.out.print( "DrawServerTcp (" + getMyIpAddress() + ") > Input server port > " ); // ポート番号入力 int port = scanner.nextInt(); // スレッドプールの生成 ExecutorService executorService = Executors.newCachedThreadPool(); // ServerSocketクラスのインスタンスをポート番号を指定して生成 try (ServerSocket serverSocket = new ServerSocket(port)) { System.out.println( "DrawServerTcp (" + getMyIpAddress() + ") > Started and Listening for connections on port " + serverSocket.getLocalPort()); while ( true ) { // ServerSocketに対する要求を待機し,それを受け取ったらSocketクラスのインスタンスからChatTaskを生成 DrawTask drawTask = new DrawTask(serverSocket.accept()); // ChatTaskのインスタンスをリストに保管 drawTasks.add(drawTask); // タスクの実行 executorService.submit(drawTask); } } catch (IOException ex) { Logger.getLogger(DrawServerTcp. class .getName()).log(Level.SEVERE, null , ex); } finally { // スレッドプールの停止 executorService.shutdown(); } } } /** * 自ホストのIPアドレス取得 * * @return 自ホストのIPアドレス */ private static String getMyIpAddress() { try { // 自ホストのIPアドレス取得 return InetAddress.getLocalHost().getHostAddress(); } catch (UnknownHostException ex) { Logger.getLogger(DrawServerTcp. class .getName()).log(Level.SEVERE, null , ex); } return null ; } /** * メッセージの同報通知(サーバ->クライアント) * * @param message メッセージ */ private synchronized void broadcast(String message) { // ChatTashのArrayListの各要素に対して drawTasks.forEach((drawTask) -> { // PrintWriter経由でメッセージ送信 drawTask.getPrintWriter().println(message); }); } private final class DrawTask implements Callable<Void> { // ソケット private Socket socket; // データ送信用Writer(サーバ->クライアント用) private PrintWriter writer = null ; // データ受信用Reader(クライアント->サーバ用) private BufferedReader reader = null ; /** * コンストラクタ * * @param socket Socketクラスのインスタンス */ DrawTask(Socket socket) { this .socket = socket; try { // Socket経由での書込用PrintWriter生成(サーバ->クライアント用) writer = new PrintWriter(socket.getOutputStream(), true ); // Soket経由での読込用BufferedReader生成(クライアント->サーバ用) reader = new BufferedReader( new InputStreamReader(socket.getInputStream())); System.out.println( "DrawServerTcp (" + getMyIpAddress() + ") > Accepted connection from " + socket.getRemoteSocketAddress()); } catch (IOException ex) { Logger.getLogger(DrawServerTcp. class .getName()).log(Level.SEVERE, null , ex); } } /** * PrintWriterのゲッタ * * @return PrintWriter */ public PrintWriter getPrintWriter() { return writer; } @Override public Void call() { try { String inputLine; // readerから一行読み込み while ((inputLine = reader.readLine()) != null ) { // 受信文をそのまま同報通知 broadcast(inputLine); //System.out.println("DrawClientTcp (" + socket.getRemoteSocketAddress() + ") > " + inputLine); } } catch (IOException ex) { Logger.getLogger(DrawServerTcp. class .getName()).log(Level.SEVERE, null , ex); } finally { System.out.println( "DrawServerTcp (" + getMyIpAddress() + ") > Terminated connection from " + socket.getRemoteSocketAddress()); try { // socket, reader, writerのclose if (socket != null ) { socket.close(); } if (reader != null ) { reader.close(); } if (writer != null ) { writer.close(); } } catch (IOException ex) { Logger.getLogger(DrawServerTcp. class .getName()).log(Level.SEVERE, null , ex); } } // ChatTaskのリストから自身を削除 drawTasks.remove( this ); return null ; } } } |
DrawClientTcp.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | package jp.ac.utsunomiya_u.is; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import javafx.application.Application; import javafx.application.Platform; import javafx.concurrent.Task; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.control.Alert; import javafx.scene.control.Button; import javafx.scene.control.ButtonType; import javafx.scene.control.Label; import javafx.scene.control.TextField; import javafx.scene.layout.GridPane; import javafx.scene.paint.Color; import javafx.scene.shape.Circle; import javafx.stage.Stage; public class DrawClientTcp extends Application { // ルートノード private final Group root = new Group(); // ソケット private Socket socket = null ; // データ送信用Writer private PrintWriter writer = null ; // データ受信用Reader private BufferedReader reader = null ; // 受信タスク private ReceiverTask receiverTask = null ; @Override public void start(Stage primaryStage) throws Exception { // Stageのタイトル primaryStage.setTitle(getClass().getName()); // Stageのサイズ primaryStage.setWidth( 800 ); primaryStage.setHeight( 800 ); // Stageの終了ボタンが押下された時の対応 primaryStage.setOnCloseRequest((event) -> { exit(); }); // Sceneインスタンス生成 Scene scene = new Scene(root); // Scene上でマウスがドラッグされた時の動作 scene.setOnMouseDragged((event) -> { if (socket != null && socket.isConnected()) { // マウスの座標から文字列生成 String str = event.getX() + "," + event.getY(); for ( int i = 0 ; i < 1000 ; ++i) { str += "," + event.getX() + "," + event.getY(); } // サーバに情報送信 writer.println(str); // マウス座標を中心とする赤い円を描画 root.getChildren().add( new Circle(event.getX(), event.getY(), 2 , Color.RED)); } }); // StageにSceneを貼付け primaryStage.setScene(scene); // IPアドレスとポート番号設定用ペインを作成し,ルートに貼付け root.getChildren().add( new NetworkConfigurePane()); // Stageの表示 primaryStage.show(); } /** * ”退室”ボタンが押下された時の処理 */ private void exit() { // タスクをキャンセル receiverTask.cancel(); try { // SocketとReaderとWriterをclose if (socket != null ) { socket.close(); } if (reader != null ) { reader.close(); } if (writer != null ) { writer.close(); } } catch (IOException ex) { new Alert(Alert.AlertType.ERROR, "ソケットを閉じることが出来ません" , ButtonType.OK).show(); } } private class NetworkConfigurePane extends GridPane { // 操作可能コンポーネント private final TextField textFieldServerIpAddress = new TextField( "localhost" ); private final TextField textFieldServerPortNumber = new TextField( "10000" ); private final Button buttonEnter = new Button( "入室" ); private final Button buttonExit = new Button( "退室" ); public NetworkConfigurePane() { // 各コンポーネントの生成 Label labelIpAddress = new Label( "サーバIPアドレス:" ); Label labelPortNumber = new Label( "サーバポート番号:" ); // 各コンポーネントの配置 GridPane.setConstraints(labelIpAddress, 0 , 0 ); GridPane.setConstraints(textFieldServerIpAddress, 1 , 0 ); GridPane.setConstraints(labelPortNumber, 0 , 1 ); GridPane.setConstraints(textFieldServerPortNumber, 1 , 1 ); GridPane.setConstraints(buttonEnter, 2 , 1 ); GridPane.setConstraints(buttonExit, 3 , 1 ); // GridPaneに各コンポーネント追加 getChildren().addAll(labelIpAddress, textFieldServerIpAddress, labelPortNumber, textFieldServerPortNumber, buttonEnter, buttonExit); // コンポーネント表示設定切替 setConnection( true ); // buttonEnter.setOnAction((event) -> { try { // textFiledServerIpAddressテキストフィールドに入力された文字列からサーバIPアドレスを指定 InetAddress serverInetAddress = InetAddress.getByName(textFieldServerIpAddress.getText()); // textFieldServerPortNumberテキストフィールドに入力された文字列からサーバポート番号を指定 int serverPortNumber = Integer.valueOf(textFieldServerPortNumber.getText()); // Socket生成 socket = new Socket(serverInetAddress, serverPortNumber); // Socket経由での書込用PrintWriter生成(クライアント->サーバ用) writer = new PrintWriter(socket.getOutputStream(), true ); // Soket経由での読込用BufferedReader生成(サーバ->クライアント用) reader = new BufferedReader( new InputStreamReader(socket.getInputStream())); // スレッドプールをSingleThreadで生成 ExecutorService executorService = Executors.newSingleThreadExecutor(); // TaskReceiver生成 receiverTask = new ReceiverTask(); // タスク実行 executorService.submit(receiverTask); // スレッドプールを停止 executorService.shutdown(); } catch (UnknownHostException ex) { new Alert(Alert.AlertType.ERROR, "IPアドレスが不正です" , ButtonType.OK).show(); } catch (NumberFormatException ex) { new Alert(Alert.AlertType.ERROR, "ポート番号が不正です" , ButtonType.OK).show(); } catch (IOException ex) { new Alert(Alert.AlertType.ERROR, "サーバに接続出来ません" , ButtonType.OK).show(); } if (socket != null && socket.isConnected()) { setConnection( false ); } }); // ”退室”ボタンが押下された時の処理 buttonExit.setOnAction((event) -> { exit(); if (socket == null || socket.isClosed()) { setConnection( true ); } }); } /** * 各コンポーネントの変更可否 * * @param connected 接続時を意味するフラグ */ private void setConnection( boolean connected) { textFieldServerIpAddress.setDisable(!connected); textFieldServerPortNumber.setDisable(!connected); buttonEnter.setDisable(!connected); buttonExit.setDisable(connected); } } /** * サーバからのメッセージを受信するためのタスク */ private class ReceiverTask extends Task<Void> { @Override protected Void call() throws Exception { String inputLine; while ((inputLine = reader.readLine()) != null ) { // 受信データを","で分解 String[] position = inputLine.split( "," ); Platform.runLater(() -> { // 1番目の要素を中心のX座標,2番目の要素を中心のY座標とする青い円を描画 root.getChildren().add( new Circle(Double.valueOf(position[ 0 ]), Double.valueOf(position[ 1 ]), 2 , Color.BLUE)); }); } return null ; } } public static void main(String[] args) { launch(args); } } |