네트워크 기초 - 소켓

Jobmania·2023년 2월 20일
0

네트워크

목록 보기
1/13
post-thumbnail

네트워크란?

  1. 네트워크란 다른 장치로 데이터를 이동시킬 수 있는 컴퓨터들과 주변 장치들의 집합입니다.

  2. 네트워크의 연결된 모든 장치들을 노드라고 합니다.

  3. 다른 노드에게 하나 이상의 서비스를 해주는 노드를 호스트라 부릅니다.

  4. 하나의 컴퓨터에서 다른 컴퓨터로 데이터를 이동시킬 때 복잡한 계층을 통해 전송되는데, 이런 복잡한 레이어의 대표적인 모델이 OSI 계층 모델입니다.

  5. OSI 계층 모델은 모두 7계층으로 이루어져 있습니다.

  6. 데이터 통신을 이해하는데 OSI 계층 모델은 상당한 역할을 하지만, 인터넷 기반의 표준 모델로 사용하는 TCP/IP 계층 모델을 주로 사용하고 있습니다.

  7. 자바에서 이야기하는 네트워크 프로그래밍은 TCP/IP모델을 사용하고 있습니다.

IP주소

  1. 모든 호스트는 인터넷 주소(Host 또는 IP 주소)라 불리는 유일한 32비트 숫자로 구성된 주소 체계를 이용하여 서로를 구분할 수 있습니다.

  2. IP 주소는 32비트 숫자를 한번에 모두를 표현하는 것이 힘들기 때문에, 8 비트씩 끊어서 표현하고, 각 자리는 1바이트로 0~255 까지의 범위를 갖게 됩니다.

  3. 32비트의 주소 체계를 IP 버전 4(IPv4) 주소라고 합니다.

  4. 오늘날 IPv4는 포화 상태이고, 이를 극복하고자 나온 것이 IP 버전 6(IPv6)입니다.

  5. IPv6는 128 비트의 주소 체계를 관리하고 있으며, 16비트씩 8부분으로 나누어 16진수 표시합니다.

  6. 각 호스트는 도메인 이름을 컴퓨터가 사용하는 주소(IP 주소)로 바꾸어 주어야 한다. 이렇게 IP 주소를 도메인 이름으로 바꾸어 주는 시스템을 DNS(Domain Name System)이라고 합니다.

포트와 프로토콜

포트

  1. 포트는 크게 두 가지로 구분되는데 컴퓨터의 주변자치를 접속하기 위한 ‘물리적인 포트’와 프로그램에서 사용되는 접속 장소인 ‘논리적인 포트’가 있습니다.

  2. 포트번호는 인터넷번호 할당 허가 위원회(IANA)에 의해 예약된 포트번호를 가지게 됩니다.

  3. 이런 포트번호를 ‘잘 알려진 포트들’라고 부릅니다.

  4. 예약된 포트번의 대표적인 예로는 80(HTTP), 21(FTP), 22(SSH), 23(TELNET)등이 있습니다.

  5. 포트번호는 0~65535까지 이며, 0~1023까지는 시스템에 의해 예약된 포트번호이기 때문에 될 수 있는 한 사용하지 않는 것이 바람직합니다.

http의 기본 포트는 80이다.
https의 기본 포트는 443이다.

프로토콜

  1. 프로토콜은 클라이언트와 서버간의 통신 규약입니다.

  2. 통신규약이란 상호 간의 접속이나 절단방식, 통신방식, 주고받을 데이터의 형식, 오류검출 방식, 코드변환방식, 전송속도 등에 대하여 정의하는 것을 말합니다.

  3. 대표적인 인터넷 표준 프로토콜에는 TCP와 UDP가 있다.

TCP와 UDP

  1. TCP/IP 계층 모델은 4계층의 구조를 가지고 있습니다.

  2. 애플리케이션, 전송, 네트워크 , 데이터 링크 계층이 있습니다.

  3. 이 중 전송계층에서 사용하는 프로토콜에는 TCP와 UDP가 있습니다.

TCP

TCP(Transmission Control Protocol)는 신뢰할 수 있는 프로토콜로서 , 데이터를 상대 측까지 제대로 전달되었는지(3 WAY HANDSHAKE) 확인 메시지를 주고 받음으로써 데이터의 송수신 상태를 점검합니다.

UDP

UDP(User Datagram Protocol)은 신뢰할 수 없는 프로토콜로서, 데이터를 보내기만 하고 확인 메시지를 주고 받지 않기 때문에 제대로 전달했는지 확인하지 않습니다

하지만 전송속도는 UDP가 빠르기 때문에 최근에는 HTTP에 UDP를 많이 적용. 대용량, 동영상서비스에 UDP를 많이 사용.

소켓에 대해서

TCP 통신방식이란?

  1. TCP란 소켓 프로그래밍 중의 하나로 스트림 통신 프로토콜이라고 부르며, 양쪽의 소켓이 연결된상태여야만 가능 하기 때문에 연결지향 프로토콜이라고도 합니다.

  2. TCP 프로토콜은 신뢰성 있는 프로토콜이기 때문에, 송신한 쪽의 데이터가 수신 측에 차례대로, 중간에 유실되는 일 없이 도착 하는 것을 의미합니다. 그러려면 수신 측과 송신 측이 미리 연결을 맺고 연결된 순서대로 데이터를 교환해야 합니다.

  3. 연결지향 방식은, 한번 연결되면 연결이 끊어질 때까지는 송신한 데이터가 차례대로 목적지의 소켓에 전달되는 신뢰성 있는 통신이 가능합니다.

  4. 이렇게 신뢰성 있는 TCP 연결을 하기 위해서는 TCP 프로그래밍에서 사용하는 라이브러리의 사용 방법과 동작 순서를 정확하게 숙지, 이해하고 있어야 합니다.

  5. 자바는 TCP 프로그래밍을 쉽게 할 수 있도록 java.net 패키지에 관련 클래스들을 미리 준비해놓고 있기 때문에, 해당 패키지의 클래스들을 알맞게 사용할 수 있어야 합니다.

소켓을 이용한 입출력 스트림 생성
1. TCP 소켓은 두 개의 네트워크 사이에서 바이트 스트림 통신을 제공합니다.
2. Socket 클래스는 바이트를 읽기 위한 메서드와 쓰기 위한 메서드를 제공합니다.
3. 두 가지 메서드를 이용하여 클라이언트와 서버간에 통신을 할 수 있습니다.

소켓

  1. 자바 프로그램은 소켓(Socket)이라는 개념을 통해서 네트워크 통신을 합니다.

  2. 소켓은 네트워크 부분의 끝 부분을 나타내며, 실제 데이터가 어떻게 전송되는지 상관하지 않고 읽기/쓰기 인터페이스를 제공합니다.

  3. 네트워크 계층과 전송 계층이 캡슐화 되어 있기 때문에 두 개의 계층을 신경 쓰지 않고 프로그램을 만들 수 있습니다.

  4. 소켓은 캘리포니아 대학교에서 빌 조이(Bill Joy)에 의해 개발되었다.

  5. 자바는 이식성과 크로스 플랫폼 네트워크 프로그램을 위해서 소켓을 핵심 라이브러리 만들습니다.

  6. TCP/IP 계층의 TCP를 지원하기 위해서 Socket, ServerSocket 클래스를 제공하고 있습니다.

  7. 클라이언트는 Socket 객체를 생성하여 TCP 서버와 연결을 시도합니다.

  8. 서버는 SocketServer 객체를 생성하여 TCP 연결을 청취하여 클라이언트와 서버가 연결됩니다..

소켓종료

  1. 소켓의 사용이 끝나면 연결을 끊기 위해서는 소켓의 close() 메서드를 호출해야 합니다.

  2. 소켓 종료는 일반적으로 finally 블록에서 처리하고, close() 메서는 IOException를 발생하기 때문에 예외처리를 반드시 해야 합니다.

  3. 소켓은 시스템에 의해 자동으로 종료되는 경우가 있습니다.

  4. 프로그램이 종료되거나, 가비지 컬렉터에 의해 처리되는 경우에 소켓이 자동으로 종료됩니다.

  5. 소켓이 시스템에 의해 자동으로 닫히는 것은 바람직 하지 않고, close() 메서드를 호출해서 정확히 소켓종료를 해야 합니다.

  6. 소켓이 닫히더라도 getIntAddress() , getPort() 메서드는 사용할 수 있으나, getInputStream(), getOutputStream() 메서드는 사용할 수 없습니다.

TCP Server Socket

  1. ServerSocket 클래스가 TCP 서버 소켓을 의미합니다.

  2. 클라이언트의 TCP 연결을 받기 위해서는 java.net.ServerSocket 클래스의 객체를 생성해야 합니다.

  3. ServerSocket 클래스는 네트워크 통신을 수행하기 위해 자신을 바로 사용하는 것이 아니라 클라이언트의 TCP 요청에 대한 Socket 객체를 생성하는 역할을 합니다.

  4. ServerSocket 객체를 생성했다면 ServerSocket 클래스의 accept() 메서드는 클라이언트의 TCP 요청이 있을 때 까지 블로킹 되는 메서드입니다.

  5. 클라이언트의 TCP 요청이 오면 accept() 메서드는 클라이언트와 통신할 수 있는 TCP 소켓을 반환합니다.

  6. 그런 후에 다른 클라이언트의 요청을 기다리게 되므로 일반적으로 accept() 메서드는 무한루프로 처리하게 됩니다.

  7. 클라이언트의 소켓과 서버에서는 accept() 메서드에 의해 반환 소켓을 가지고 스트림을 생성하여 통신하게 됩니다.


Test 1.

/// Server

public class Server {

    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(9500);

            while(true){       

                // 대기 연결을 기다리는 중
                System.out.println("연결 기다리는 중 ! ");
                Socket socket = serverSocket.accept();
                InetSocketAddress isa = (InetSocketAddress) socket.getRemoteSocketAddress();
                System.out.println("연결 수락됨. 이름은" + isa.getAddress());

                // 소켓 => 서버
                BufferedReader reader = 
                		new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String line = reader.readLine();
                System.out.println("서버에서 받은 메시지 : " + line);

                // 서버 => 소켓
                PrintWriter writer = 
                		new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
                writer.println("Server to Client"+line);
                writer.flush(); // 버퍼를 비운다 ==> 전송!!

            }
        } catch (IOException e) {
            System.out.println(e.getMessage());
            throw new RuntimeException(e);
        }
    }
}

/// client
public class Client {
    public static void main(String[] args) {
        try {
            Socket socket = new Socket("127.0.0.1", 9500);  // 접속하려는 ip,port
            System.out.println("연결 성공..");

            //             1. 클라이언트 => 소켓
            String msg = " <<안녕하세요!>>";
            PrintWriter writer = 
            		new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
            writer.println(msg);
            writer.flush(); // 버퍼를 비운다 ==> 전송!!


//           2. 소켓 => 클라이언트
            BufferedReader reader = 
            		new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String line = reader.readLine();
            System.out.println("서버에서 받은 메시지 : " + line);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

localhost 9500번 port에서 Client 측의 메세지(or 파일)을 서버가 받고 이를 다시 클라이언트에게 확인하는 단순한 구조

Test 2.

// server
public class MyServer {
    public static void main(String[] args) throws IOException {
        BufferedReader in = null;
        PrintWriter out = null;

        ServerSocket serverSocket = null;
        Socket socket = null;

//        키보드 입력을 받기 위함.
        Scanner scanner = new Scanner(System.in);
        try {
            System.out.println("[Server실행] Client 연결 대기중...");
            serverSocket = new ServerSocket(8000);  
            socket = serverSocket.accept();  // 대기중~~~

            // 클라이언트 연결
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            out = new PrintWriter(socket.getOutputStream());


            while(true){
                String inputMessage = in.readLine(); // 수신데이터 한줄씩 읽기
                
                if("quit".equalsIgnoreCase(inputMessage)) break; // quit 수신시 종료

                System.out.println("From Client: " + inputMessage);
                System.out.println("전송하기 >>>>  ");
                String outputMessage = scanner.nextLine(); // 전송할 데이터 입력.....
                out.println(outputMessage);
                out.flush(); // 소켓에 전송....
                if("quit".equalsIgnoreCase(outputMessage)) break; // 종료

            }


        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
        // 연결이 끝나면 all  close
            scanner.close();
            if (serverSocket != null)  serverSocket.close();
            if (socket != null) socket.close();
            System.out.println("연결종료");
        }


    }
}
// client
public class MyClient {
    public static void main(String[] args) {

        BufferedReader in = null;
        PrintWriter out = null;

        Socket socket = null;
        Scanner scanner = new Scanner(System.in);

        try {
            socket = new Socket("127.0.0.1", 8000);

            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            out = new PrintWriter(socket.getOutputStream());

            while(true) {
                System.out.print("전송하기>>> ");
                String outputMessage = scanner.nextLine();
                out.println(outputMessage);
                out.flush();
                if ("quit".equalsIgnoreCase(outputMessage)) break;

                String inputMessage = in.readLine();

                System.out.println("From Server: " + inputMessage);
                if ("quit".equalsIgnoreCase(inputMessage)) break;
            }


        } catch (IOException e) {
            System.out.println(e.getMessage());
        } finally {
            try {
                scanner.close();
                if (socket != null) socket.close();
                System.out.println("서버연결종료");
            } catch (IOException e) {
                System.out.println("소켓통신에러");
            }
        }
    }
}

profile
HelloWorld에서 RealWorld로

0개의 댓글