활용) GUI 채팅프로그램
2019. 1. 30. 23:03ㆍJAVA
#Step1 폴더 구성
#Step2 서버 자바 프로젝트
-> Main.java와 client.java로 나뉜다.
① Main.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 | package com.chat; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.util.Iterator; import java.util.Vector; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import javafx.application.Application; import javafx.application.Platform; import javafx.geometry.Insets; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.TextArea; import javafx.scene.layout.BorderPane; import javafx.scene.text.Font; import javafx.stage.Stage; public class Main extends Application { /* * 여러 개의 Thread를 효율적으로 관리하는 대표적인 라이브러리 -> ThreadPool로 처리하게 되면 Thread숫자를 제한하기 떄문에 * 서버폭증에 대비할 수 있다. */ public static ExecutorService threadPool; /* 접속한 클라이언트들을 관리한다 -> 일종의 배열 */ public static Vector<client> clients = new Vector<client>(); ServerSocket serverSocket; /* 서버를 구동시켜서 클라이언트의 연결을 기다리는 메소드 */ public void startServer(String IP, int port) { try { serverSocket = new ServerSocket(); /* 특정 클라이언트의 접속을 기다린다 */ serverSocket.bind(new InetSocketAddress(IP, port)); } catch (Exception e) {// 오류 발생 if (!serverSocket.isClosed()) {// serverSocket이 닫혀 있는 상황이 아니라면 stopServer(); } return; } // 클라이언트가 접속할때 까지 기다린다. Runnable thread = new Runnable() { @Override public void run() { while (true) { try { Socket socket = serverSocket.accept();// 클라이언트의 접속을 기다린다. clients.add(new client(socket)); System.out.println("[클라이언트 접속]" + socket.getRemoteSocketAddress() + ":" + Thread.currentThread().getName()); } catch (Exception e) { if (!serverSocket.isClosed()) { stopServer(); } break; } } } }; /* threadpool을 초기화 한 다음, 첫 번째 thread를 넣어준다. */ threadPool = Executors.newCachedThreadPool(); threadPool.submit(thread); }// startServer() /* 서버의 동작을 중지시키는 메소드 */ public void stopServer() { try { // 현재 작동 중인 모든 소켓 닫기 /* Iterator통해서 모든 클라이언트에 개별적으로 접근할 수 있도록 할 수 있다 */ Iterator<client> iterator = clients.iterator(); while (iterator.hasNext()) { client client = iterator.next(); client.socket.close(); iterator.remove(); } // serversocket 객체 닫기 if (serverSocket != null && !serverSocket.isClosed()) { serverSocket.close(); } // threadPool 종료하기 if (threadPool != null && threadPool.isShutdown()) { threadPool.isShutdown(); } } catch (Exception e) { e.printStackTrace(); } }// stopServer() /* 화면설정 */ @Override public void start(Stage primaryStage){ BorderPane root = new BorderPane(); root.setPadding(new Insets(5)); TextArea textArea = new TextArea(); textArea.setEditable(false); textArea.setFont(new Font("나눔고딕",15)); root.setCenter(textArea); Button toggleButton = new Button("시작하기"); toggleButton.setMaxWidth(Double.MAX_VALUE); BorderPane.setMargin(toggleButton, new Insets(1,0,0,0)); root.setBottom(toggleButton); String IP ="127.0.0.1"; int port = 2980; toggleButton.setOnAction(event->{ if(toggleButton.getText().equals("시작하기")) { startServer(IP, port); Platform.runLater(()->{ String message = String.format("[서버 시작]\n",IP,port); textArea.appendText(message); toggleButton.setText("종료하기"); }); }else { stopServer(); Platform.runLater(()->{ String message = String.format("[서버 종료]\n",IP,port); textArea.appendText(message); toggleButton.setText("시작하기"); }); } }); Scene scene = new Scene(root,400,400); primaryStage.setTitle("Chat Server"); primaryStage.setOnCloseRequest(event->stopServer()); primaryStage.setScene(scene); primaryStage.show(); }// start() public static void main(String[] args) { launch(args); }// main() } | cs |
② client.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 | package com.chat; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; public class client { Socket socket; // 컴퓨터와 네트워크 통신을 위함 public client(Socket socket) {// 생성자 this.socket = socket; receive(); }// client() /* 클라이언트로부터 메세지를 전달받는 메소드 */ public void receive() { Runnable thread = new Runnable() {// 스레드 생성 @Override public void run() { try { while (true) { /* 메세지 받기 위해 intPutStream */ InputStream in = socket.getInputStream(); byte[] buffer = new byte[512]; // 한번에 512byte만큼 전달 받을 수 있게 설정 int length = in.read(buffer); while (length == -1) throw new IOException();// 오류 발생 처리 /* getRemoteSocketAddress(): 현재 접속한 클라이언트의 아이피 주소와 같은 주소를 GET */ System.out.println("[메세지 수신 성공]" + socket.getRemoteSocketAddress() + ":" + Thread.currentThread().getName()); /* 전달 받은 값을 한글도 가능하도록 설정 */ String message = new String(buffer, 0, length, "UTF-8"); /* 전달 받은 메세지를 다른 클라이언트로 보낼 수 있도록 설정 */ for (client client : Main.clients) { client.send(message); } } } catch (Exception e) { try { System.out.println("[메세지 수신 오류]" + socket.getRemoteSocketAddress() + ":" + Thread.currentThread().getName()); Main.clients.remove(client.this); socket.close(); } catch (Exception e2) {// 오류가 발생 했을때 더욱 더 상세히 처리 e2.printStackTrace(); } } } }; Main.threadPool.submit(thread);// 만들어진 thread를 threadPool에 보낸다 }// receive() /* 클라이어트로 메세지를 보내는 메소드 */ public void send(String Message) { Runnable thread = new Runnable() { @Override public void run() { try { /* 메세지를 보내기 위해 OutPutStream */ OutputStream out = socket.getOutputStream(); byte[] buffer = Message.getBytes("UTF-8"); /* 메세지 송신에 성공하였다면 buffer 담긴 내용을 서버로 보내고, flush를 통해 성공된 부분까지 알려줌 */ out.write(buffer); out.flush(); } catch (Exception e) { try { System.out.println("[메세지 송신 오류]" + socket.getRemoteSocketAddress() + ":" + Thread.currentThread().getName()); /* 오류가 발생했을때 해당 클라이언트를 제거 */ Main.clients.remove(client.this); socket.close();// 닫아버림 } catch (Exception e2) { e2.printStackTrace(); } } } }; Main.threadPool.submit(thread); }// send() }// client{} | cs |
③ 실행화면
#Step3 클라이언트 폴더
-> 채팅서버에 접속하는 클라이언트를 설정
①Main,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 | package application; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import javafx.application.Application; import javafx.application.Platform; import javafx.geometry.Insets; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.TextArea; import javafx.scene.control.TextField; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import javafx.stage.Stage; public class Main extends Application { Socket socket; TextArea textArea; // 클라이언트 동작 메소드 public void startClient(String IP, int port) { Thread thread = new Thread() { public void run() { try { socket = new Socket(IP, port); receive(); } catch (Exception e) { // TODO: handle exception if (!socket.isClosed()) { stopClient(); System.out.println("[서버 접속 실패]"); Platform.exit();// 프로그램 종료 } } } }; thread.start(); } // 클라이언트 종료 메소드 public void stopClient() { try { if (socket != null && !socket.isClosed()) { socket.close(); } } catch (Exception e) { e.printStackTrace(); } } // 서버로부터 메세지를 전달받는 메소드 public void receive() { while (true) { try { InputStream in = socket.getInputStream(); byte[] buffer = new byte[512]; int length = in.read(buffer); if (length == -1) throw new IOException(); String message = new String(buffer, 0, length, "UTF-8"); Platform.runLater(() -> { textArea.appendText(message); }); } catch (Exception e) { // TODO: handle exception stopClient(); break; } } } // 서버로 메세지를 보내는 메소드 public void send(String message) { Thread thread = new Thread() { public void run() { try { OutputStream out = socket.getOutputStream(); byte[] buffer = message.getBytes("UTF-8"); out.write(buffer); out.flush(); } catch (Exception e) { // TODO: handle exception stopClient(); } } }; thread.start(); } // 동작 메소드 @Override public void start(Stage primaryStage) { BorderPane root = new BorderPane(); root.setPadding(new Insets(5)); HBox hBox = new HBox(); hBox.setSpacing(5); TextField userName = new TextField(); userName.setPrefWidth(150); userName.setPromptText("닉네임을 입력하세요"); HBox.setHgrow(userName, Priority.ALWAYS); TextField IPText = new TextField("127.0.0.1"); TextField portText = new TextField("2980"); portText.setPrefWidth(80); IPText.setPrefWidth(150);// 픽셀단위 hBox.getChildren().addAll(userName, IPText, portText); root.setTop(hBox); textArea = new TextArea(); textArea.setDisable(false); root.setCenter(textArea); TextField input = new TextField(); input.setPrefWidth(Double.MAX_VALUE); input.setDisable(true); /* 텍스트 입력창 동작 */ input.setOnAction(event -> { send(userName.getText() + ":" + input.getText() + "\n"); input.setText(""); input.requestFocus(); }); /* 보내기 버튼 동작 */ Button sendBtn = new Button("전송"); sendBtn.setDisable(true); sendBtn.setOnAction(event -> { send(userName.getText() + ":" + input.getText() + "\n"); input.setText(""); input.requestFocus(); }); /* 접속 버튼 동작 */ Button loginBtn = new Button("접속"); loginBtn.setOnAction(event -> { if (loginBtn.getText().equals("접속")) { int port = 2980; try { port = Integer.parseInt(portText.getText()); } catch (Exception e) { e.printStackTrace(); } startClient(IPText.getText(), port); Platform.runLater(() -> { textArea.appendText("[채팅 접속]\n"); }); loginBtn.setText("종료"); input.setDisable(false); sendBtn.setDisable(false); input.requestFocus(); }else { stopClient(); Platform.runLater(()->{ textArea.appendText("[채팅 종료]\n"); }); loginBtn.setText("접속"); input.setDisable(true); sendBtn.setDisable(true); } }); BorderPane pane = new BorderPane(); pane.setLeft(loginBtn); pane.setCenter(input); pane.setRight(sendBtn); root.setBottom(pane); Scene scene = new Scene(root,400,400); primaryStage.setTitle("Chat Client"); primaryStage.setScene(scene); primaryStage.setOnCloseRequest(event-> stopClient()); // 닫기 버튼을 눌렸을때 stopClient메소드 호출 primaryStage.show(); loginBtn.requestFocus(); } // 실행 메소드 public static void main(String[] args) { launch(args); } } | cs |
② 실행화면
#Step4 프로그램 동작
>>서버가 시작되지 않은 상태에서 클라이언트만 실행시킬 경우 오류 발생
>>각 클라이언트가 접속할 때 Thread 생성
'JAVA' 카테고리의 다른 글
2019.02.07 JAVA로 DB연동하기-Service객체 사용하기(Proxy) (0) | 2019.02.07 |
---|---|
2019.02.07 JAVA로 DB연동하기 (0) | 2019.02.07 |
2019.01.30 JAVA에서 HTML문서 만들기 (0) | 2019.01.30 |
2018.01.25 JDBC: 데이터베이스 연결 (0) | 2019.01.25 |
2019.01.21 예제) 데이터 입력 및 데이터 검색(Map,List) (0) | 2019.01.22 |