728x90
반응형
[Java] 98. 코드 리팩토링(1:1 양방향 통신-클라이언트 측)
*자세한 해석, 설명은 아래 글을 참고하자.
https://whatsthatsound.tistory.com/193
(1) MultiThreadClient
package ch05;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
// 1단계 - 함수로 분리해서 리팩토링 진행
public class MultiThreadClient {
public static void main(String[] args) {
System.out.println("===== 클라이언트 실행 =====");
try (Socket socket = new Socket("localhost",5004)){
System.out.println("=====Connected to the server=====");
PrintWriter socketWriter =
new PrintWriter(socket.getOutputStream());
BufferedReader socketReader =
new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedReader keyboardReader =
new BufferedReader(new InputStreamReader(System.in));
startWriteThread(socketWriter,keyboardReader);
startReadThread(socketReader);
System.out.println("main 스레드 작업 완료 ...");
} catch (Exception e) {
e.printStackTrace();
}
} // end of main
// 1. 서버로부터 데이터를 읽어들이는 스레드
private static void startReadThread(BufferedReader socketReader) {
Thread readThread = new Thread(()->{
try {
String serverMessage;
while((serverMessage=socketReader.readLine())!=null) {
System.out.println("서버에서 온 MSG : "+serverMessage);
}
} catch (Exception e) {
e.printStackTrace();
}
});
readThread.start();
waitForThreadToEnd(readThread);
}
// 2. 서버에게 데이터를 보내는 스레드
private static void startWriteThread(PrintWriter sockerWriter,BufferedReader keyboardReader) {
Thread writeThread = new Thread(()->{
try {
String clientMessage;
while((clientMessage=keyboardReader.readLine())!=null) {
sockerWriter.println(clientMessage);
}
} catch (Exception e) {
e.printStackTrace();
}
});
writeThread.start();
waitForThreadToEnd(writeThread);
}
// 3. 워커 스레드가 종료될 때까지 기다리는 메서드
private static void waitForThreadToEnd(Thread thread) {
try {
thread.join();
} catch (Exception e) {
e.printStackTrace();
}
}
} // end of class
(2) AbstractClient(추상 클래스)
package ch05;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
// 2단계 - 상속 활용 리팩토링 단계
public abstract class AbstractClient {
private Socket socket;
private BufferedReader socketReader;
private PrintWriter socketWriter;
private BufferedReader keyboardReader;
// set 메서드
// 메서드 의존 주입 (멤버 변수에 참조 변수 할당)
protected void setSocket(Socket socket) {
this.socket = socket;
}
// get 메서드
protected Socket getSocket() {
return this.socket;
}
// 실행의 흐름이 필요하다.
// final - 상속 받은 자식 클래스에서 수정이 불가
public final void run() {
try {
setupClient();
setupStream();
startService();
} catch (Exception e) {
} finally {
cleanup();
}
}
// 1. 포트 번호 할당
protected abstract void setupClient() throws IOException;
// 2. 스트림 초기화
private void setupStream() throws IOException{
socketReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
socketWriter = new PrintWriter(socket.getOutputStream(),true);
keyboardReader = new BufferedReader(new InputStreamReader(System.in));
}
// 3. 서비스 시작
private void startService() {
Thread writeThread = createWriteThread();
Thread readThread = createReadThread();
writeThread.start();
readThread.start();
try {
readThread.join();
writeThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 4. 캡슐화
private Thread createWriteThread(){
return new Thread(()->{
try {
String msg;
while((msg=keyboardReader.readLine())!=null) {
socketWriter.println(msg);
socketWriter.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
});
}
private Thread createReadThread() {
return new Thread(()->{
try {
String msg;
while((msg=socketReader.readLine())!=null) {
System.out.println("client 측 msg : "+msg);
}
} catch (Exception e) {
e.printStackTrace();
}
});
}
// 캡슐화 - 소켓 자원 종료
private void cleanup() {
try {
if(socket!=null) {
socket.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
(3) MyClient
package ch05;
import java.io.IOException;
import java.net.Socket;
// 2 -1 상속을 활용한 구현 클래스 설계 하기
public class MyClient extends AbstractClient{
@Override
protected void setupClient() throws IOException {
// 추상클래스: 자식 클래스는 부모 클래스에게 기능을 상속받아,
// 그 기능을 확장하거나 사용한다.
// 클라이언트측 소켓 통신 --- 준비물 : 소켓
super.setSocket(new Socket("localhost",5000));
System.out.println(">>> Client was connected on port 5000 <<<");
}
public static void main(String[] args) {
MyClient myClient = new MyClient();
myClient.run();
}
}
728x90
반응형
'Java > 네트워크 통신' 카테고리의 다른 글
[Java] 100. 네트워크 프로토콜 (0) | 2024.05.24 |
---|---|
[Java] 99. 1:N 양방향 통신 (0) | 2024.05.24 |
[Java] 97. 코드 리팩토링 (1:1 양방향 통신-서버측) (0) | 2024.05.23 |
[Java] 96. 1:1 양방향 통신(채팅 기본 기능 구현) (0) | 2024.05.22 |
[Java] 95. 1:1 양방향 통신 (서버 측) (0) | 2024.05.22 |