JAVA

자바 57강. 소켓 기본 통신

JJJAEOoni 2022. 2. 14. 13:58
반응형

 

통신을 할 때 어떤 프로그램과 통신할지

정하기 위해서는 포트 번호가 필요한데,

socket이 포트 번호를 만들어준다.

 

socket 통신이 바로 프로그램을 결정하는 통신인 것이다.

 

socket은 OS가 가지고 있는 라이브러리이다.

이 라이브러리를 자바에서 땡겨쓰는 것을 System calll이라고 한다.

 

시스템 호출(system call) : 운영 체제의 커널이 제공하는 서비스에 대해,

응용 프로그램의 요청에 따라 커널에 접근하기 위한 인터페이스

 

소켓통신은 OS 양 끝단에 소켓 라이브러리를 불러와서

양 끝단에 포트를 두고

목적지 IP 주소를 통해 통신하는 것이다.

 


 

소켓이 하나씩만 있을 때 이 통신의 문제점이 무엇일까?

다른 클라이언트가 서버와 통신하려고 할 때 불가능하다.

 

서버 소켓과 연결한 후 새로운 소켓을 생성한다.

연결이 끝나면 서버소켓과 연결된 선은 제거하고

새로운 소켓과 연결해준다.

 

서버 소켓은 연결의 역할만 해주어야

다른 클라이언트가 통신을 요청할 때

받을 수 있기 때문이다.

서버의 입장에서는 클라이언트마다 소켓이 만들어진다.

즉, 소켓이 생길 때마다 스레드가 필요한 것이다.

서버의 입장에서는 3개의 스레드가 필요하다.

 

1번 소켓의 역할은 누가 들어오나 지켜보다가

클라이언트가 들어오면

새로운 소켓을 만들어 연결해준다.

 

2번은 클라이언트 A와 통신하기 위한,

3번은 클라이언트 B와 통신하기 위한 소켓이다.

 

이때 1번 소켓에는 스레드가 하나만 필요하지만

2번과 3번은 스레드가 2개씩 필요하다.

전이중 통신을 할 때 읽고, 쓰는 스레드가 필요한 것이다.

 

전이중 통신 : 동시에 통신 가능(쓰면서 읽기)

ex. 전화기

=> 스레드 2개 필요!

 

반이중 통신 : 한쪽에서 보낼 때 다른 쪽은 읽기만 가능

ex. 무전기

=> 스레드 1개 필요!

 

단방향 통신 : 쓰거나 읽기 중 하나만 가능

한쪽으로만 전송

 


 

첫 번째 예제.

 

main 스레드 하나로 가능한 프로그램을 만들어보자.

 

서버 소켓에서는 읽기만 하고,

클라이언트 소켓은 쓰기만 한다.

이때 이 서버 소켓은 내부적으로 while이 돌며

멈추지 않고 클라이언트가 접속하는지 지켜보고 있다.

종료되지 않는 프로그램인 데몬인 것이다.

 

serverSocket.accept( ) 메서드로 while이 돌기 시작하며

클라이언트가 접속하면 새로운 소켓을 return 한다.

package site.metacoding.chat;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

public class MyServerSocket {

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

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

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

            reader = new BufferedReader(
                    new InputStreamReader(socket.getInputStream()) // socket 선 = conn
            );

            String inputData = reader.readLine();
            System.out.println("받은 메시지 : " + inputData);
            System.out.println("클라이언트 연결됨");
        } 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.BufferedWriter;
import java.io.OutputStreamWriter;
import java.net.Socket;

public class MyClientSocket {

    Socket socket;
    BufferedWriter writer;

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

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

            // 마지막 메세지 끝에는 \n이 꼭 필요함
            writer.write("안녕 \n"); // 버퍼에 담김
            writer.flush(); // 버퍼가 가득 차지 않았기 때문에 비워줘야 함
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

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

프로그램을 실행할 때는 두 가지 main파일 모두 실행시켜야 한다.

 

File -> Duplicate Workspace에서

같은 워크스페이스를 열고

서버 소켓을 실행한 뒤

클라이언트 소켓을 실행시켜준다.

그러면 서버 소켓에

성공적으로 통신이 진행되어

받은 메시지를 출력해준다.

 

 

 

 

 

[출처]

 

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

 

반응형