JAVA

자바 59강. 전이중 통신

JJJAEOoni 2022. 2. 15. 11:03
반응형

서버에서도 메세지를 보낼 수 있고,

클라이언트에서도 메세지를 보낼 수 있는

통신을 해보자.

 

서버 소켓에서

메인 스레드는 키보드의 입력을 받아

BufferedReader를 하고

새로운 스레드로 BufferedWriter를 한다.

 

Read를 하는동안 메인 스레드가

while을 돌며 바쁘기 때문에

새로운 스레드를 만들어주는 것이다.

 

클라이언트 소켓에서는

새로운 스레드를 만들어

서버 소켓으로부터 통신 오는

메세지를 읽는 BufferedReader를 만들어야 한다.

package site.metacoding.chat;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class MyServerSocket {

    // OS의 socket 라이브러리 기반 System call
    ServerSocket serverSocket; // 연결하는지 지켜보는 리스너(연결 => 세션이 만들어짐 => 인증됨!)
    Socket socket; // 메시지 통신
    BufferedReader reader;

    // 추가(클라이언트에게 메시지 보내기)
    BufferedWriter writer;
    Scanner scan;

    public MyServerSocket() {
        // 통신은 무조건 예외가 발생할 수 있음!
        try {
            // 1. 서버소켓 생성(리스너)
            // 잘 알려진 포트 : 0 ~ 1023
            serverSocket = new ServerSocket(1077); // 내부적으로 while이 돈다.
            System.out.println("서버 소켓 생성됨");
            System.out.println("aaa를 입력하면 종료됩니다.");

            // 종료되지 않는 프로그램 -> 데몬(main 스레드)
            // 내부적으로 accept가 새로운 소켓을 만들어서 return하여 연결해줌
            // 이때 소켓의 포트번호는 사용하지 않는 포트 랜덤지정(OS에게 맡김)
            // 포트번호 0 ~ 65536
            socket = serverSocket.accept(); // while을 돌면서 대기, 실제로 while 도는 메서드

            // 새로운 소켓을 알아야 버퍼를 달고 통신, 순서 중요
            reader = new BufferedReader(
                    new InputStreamReader(socket.getInputStream()) // socket 선 = conn
            );

            // 메시지 보내기
            scan = new Scanner(System.in);
            writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));

            new Thread(() -> {
                // 익명 클래스 : 다른 공간이라서 try-catch 따로 걸어줘야함
                while (true) {
                    try {
                        String inputData = scan.nextLine();
                        writer.write(inputData + "\n");
                        writer.flush();

                        if (inputData.equals("aaa")) {
                            break;
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();

            // 메시지 반복해서 받는 서버 소켓 - main 스레드
            while (true) {
                // System.out.println("클라이언트 연결됨");
                String inputData = reader.readLine();
                System.out.println("클라이언트 -> 서버 : " + inputData);

                if (inputData.equals("aaa")) {
                    break;
                }
            }

        } catch (Exception e) {
            System.out.println("통신 오류 발생 : " + e.getMessage());
            // e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new MyServerSocket();
        System.out.println("main 종료");
    }
}

 

package site.metacoding.chat;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Scanner;

import javax.swing.event.SwingPropertyChangeSupport;

public class MyClientSocket {

    Socket socket;
    BufferedWriter writer;
    BufferedReader reader;
    Scanner scan;
    String getMsg;

    public MyClientSocket() {
        try {

            // 스캐너 달고(반복x), 키보드로부터 입력 받는 부분(반복o)
            scan = new Scanner(System.in);

            // IP주소, 포트번호
            // 서버소켓과 연결
            socket = new Socket("localhost", 1077);

            writer = new BufferedWriter(
                    new OutputStreamWriter(socket.getOutputStream()));

            reader = new BufferedReader(
                    new InputStreamReader(socket.getInputStream()));

            // 메시지 읽기
            new Thread(() -> {
                while (true) {
                    try {
                        String inputData = reader.readLine();
                        System.out.println("서버 -> 클라이언트 : " + inputData);

                        if (inputData.equals("aaa")) {
                            break;
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();

            while (true) {
                // 순차적이라서 스레드 필요 없음
                getMsg = scan.nextLine();

                // 마지막 메세지 끝에는 \n이 꼭 필요함
                writer.write("Msg : " + getMsg + " \n"); // 버퍼에 담김
                writer.flush(); // 버퍼가 가득 차지 않았기 때문에 비워줘야 함

                if (getMsg.equals("aaa"))
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new MyClientSocket();
    }
}

 

 

 

[출처]

 

https://cafe.naver.com/metacoding

 

메타코딩 : 네이버 카페

코린이들의 궁금증

cafe.naver.com

 

메타 코딩 유튜브

https://www.youtube.com/c/%EB%A9%94%ED%83%80%EC%BD%94%EB%94%A9

 

메타코딩

문의사항 : getinthere@naver.com 인스타그램 : https://www.instagram.com/meta4pm 깃헙 : https://github.com/codingspecialist 유료강좌 : https://www.easyupclass.com

www.youtube.com

 

반응형