Java
Network
인터넷은 어떻게 동작하는가? - Web 개발 학습하기 | MDN
이 글에서는 인터넷의 개념과 작동 원리에 대해 설명합니다.
developer.mozilla.org
네트워크란 쉽게 말해 하나의 망 입니다. 그리고 그 망을 이용하여 서로 다른 컴퓨터들을 연결합니다. 라우터에 의하여 컴퓨터들은 네트워크를 형성하며, 이러한 라우터들이 ISP 에 연결되어 더욱 큰 네트워크를 형성합니다. 컴퓨터간의 정보 교환은 아주 방대한 양이며, 무질서할 수 있는데 이를 해결하기 위해 우리는 일종의 약속을 해야합니다. 그러한 약속을 프로토콜(Protocol) 이라 합니다.
프로토콜의 종류
1.IP [ Internet Protocol ]
2.TCP [ Transmission Control Protocol ]
3.UDP [ User Datagram Protocol ]
4.SMTP [ Simple Mail Transfer Protocol ]
5.FTP [ File Transfer Protocol ]
6.HTTP [ Hyper Text Transfer Protocol ]
자바에서 프로토콜을 이용하여 데이터를 처리해봅시다. 오늘은 TCP 와 UDP 를 이용하겠습니다.
TCP (Tranmission Control Protocol)
TCP 는 마치 전화의 형식과 비슷합니다. 누군가에게 전화를 걸 때 상대방이 받지 않는다면 전화를 연결할 수 없습니다. 상대방이 전화를 받아야 통화를 시작할 수 있는것 입니다. TCP 의 정보전달 방식도 이와 비슷합니다. 정보를 보내는 쪽을 Client 라고하며, 받는쪽을 Server 라고 합니다.
클라이언트는 서버의 IP 주소와 포트번호를 알아야 정보를 보낼 수 있습니다. 또한 클라이언트는 정보를 전달하기 위해 소켓을 생성해야 하며, 소켓에서 정보를 내보내야 합니다. 반대로 서버는 서버소켓을 만들고, 그 안쪽에 소켓을 만듭니다. 이 안쪽 소켓으로 클라이언트가 접속하여 정보를 입력해주어야 합니다.
TCP 통신을 하기 이전에 용어 2가지만 정리하고 넘어갑시다.
용어정리
1. IP주소
그 컴퓨터의 고유한 주소(숫자)로, 약 42억개정도 존재합니다(IPv4) 또한 주소는 문자열로 표현됩니다.
2. port 번호
그 컴퓨터 안에서의 프로그램의 고유번호로 약 6만 5천개 정도 존재합니다. 인터넷을 사용할 수 있는 프로그램은 한가지가 아닙니다. 그렇기 때문에 어떠한 프로그램이 인터넷과 연결할지 정해야 하는데, 그때 사용되는 번호입니다. 단, 0~1024 번까지는 사용 하지 않는게 권장됩니다. 보통 10000번대 이상으로 사용하는것이 좋습니다.
IP주소 알아보기
TCP/IP 를 통해 통신을 한다면, IP 를 통해 네트워크의 목적지를 정확히 알 수 있으며, TCP 를 통해 데이터의 신뢰성을 확보할 수 있습니다. 즉, 통신을 위해서는 먼저 데이터를 전달하고자 하는곳의 IP 주소를 알아야 합니다. 다음 코드를 봅시다.
try {
System.out.println(InetAddress.getLocalHost().getHostAddress());
-- 1
System.out.println(InetAddress.getLocalHost().getHostName());
-- 2
System.out.println(InetAddress.getLocalHost());
System.out.println(InetAddress.getLoopbackAddress().getHostAddress());
-- 3
System.out.println(InetAddress.getLoopbackAddress().getHostName());
-- 4
} catch (UnknownHostException e) {
System.out.println("호스트를 찾을 수 없습니다."); -- 5
}
예제에서는 서버 프로그램과 클라이언트 프로그램이 한 프로그램에서 통신하기 때문에 두 프로그램에서 통신하는 컴퓨터는 본 컴퓨터 1대라고 하겠습니다.
서버용 프로그램 작성하기
TCP 의 통신을 위해서는 서버와 클라이언트가 필요합니다. 그래서 서버용 프로그램을 먼저 만들어봅시다.
try {
ServerSocket serverSocket = new ServerSocket(10001);
System.out.println("서버소켓 생성");
-- 1
System.out.println("클라이언트의 접속을 기다리는 중 . . .");
Socket socket = serverSocket.accept();
-- 2
System.out.println("클라이언트 접속 완료!");
-- 3
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader reader = new BufferedReader(isr);
-- 4
while(true) {
String msg = reader.readLine();
-- 5
if(msg == null) break;
System.out.println("받은 메시지 : " + msg);
}
System.out.println("모든 접속 종료");
reader.close();
} catch (IOException e) {
System.out.println("입출력 오류");
} -- 6
- ServerSocket 클래스를 이용하여 서버소켓 객체를 생성해줍니다. 객체의 생성자 파라미터로 포트번호를 넘겨주어, 클라이언트가 메시지를 전달할 때 지정한 포트번호로 넘겨주도록 합니다.
- 데이터를 저장할 소켓을 하나 만들어주고, accept() 메서드를 통해 클라이언트의 서버접속 유무를 판단하여 정보를 받아올 수 있는 상태가 될 수 있습니다. 클라이언트가 서버에 접속하지 않는다면 접속할때까지 기다립니다.
- 만일 이 코드로 넘어왔다면 클라이언트의 접속이 완료되었다는 의미입니다.
- 접속이 완료되었으니, 클라이언트의 데이터를 읽어올 수 있는 InputStream 을 열어줍시다. 그리고 열린 바이트스트림을 받아오기 편하게 문자 스트림 InputStreamReader 로 변환해준 뒤, 보조 스트림 BufferedReader 로 다시 변환시켜 줍시다.
- 보조스트림의 메서드 readLine() 을 활용하여 데이터를 읽어와 문자열 변수에 저장해줍니다. 단, readLine() 메서드 또한 accept() 와 같이 읽어올 데이터가 없다면 보내줄때까지 기다립니다. 그런데, if 문 안쪽의 조건을 보면 데이터의 값이 없을 때, 즉 null 값을 반환할때 while 문을 빠져나가도록 되어있습니다. 보내줄때까지 기다리는데 언제 null 값을 반환할까요? 그건 바로 스트림이 끊어졌을 때를 의미합니다. 클라이언트에서 데이터를 보내줄때, OutputStream 을 통해 보내주게 되는데, 이 스트림이 닫히게 되면 readLine() 은 null 을 반환하게 됩니다.
- 입력이 모두 끝났다면, close() 메서드로 스트림을 닫아줍시다. 또한 try-catch 문을 활용하여 발생할 수 있는 에러의 예외처리도 해줍니다.
클라이언트용 프로그램 작성하기
String serverIP = "localhost";
-- 1
try {
Socket socket = new Socket(serverIP,10001);
System.out.println("서버와 연결이 되었습니다.");
-- 2
OutputStream os = socket.getOutputStream();
PrintWriter writer = new PrintWriter(os);
System.out.println("스트림 연결 성공! ... 데이터 전송 가능");
-- 3
Scanner scan = new Scanner(System.in);
while(true) {
System.out.print("보낼 메시지를 입력하세요(exit를 입력하면 종료)");
String msg = scan.nextLine();
if(msg.equalsIgnoreCase("exit")) break;
writer.println(msg);
writer.flush();
-- 4
}
writer.close();
} catch (IOException e) {
System.out.print("입출력 오류");
} -- 5
- 클라이언트가 서버에 접속하기 위해서는 서버의 IP 주소와 포트번호가 필요합니다. 이 예제에서는 서버의 IP 주소가 클라이언트의 컴퓨터와 동일하기 때문에 "localhost" 를 사용하였습니다.
- 서버와 연결하기 위한 소켓을 만들어줍시다. 소켓을 만들어줄 때는 서버의 IP 주소와 포트번호를 전달해주어야 합니다. 아까 전 서버용 프로그램 예제에서 서버 프로그램을 만들 때, 포트번호를 10001로 지정해주었기 때문에 여기서도 포트번호를 10001로 지정해주었습니다.
- 정보를 서버로 전달해주기 위한 OutputStream 을 생성합시다. 또한 보조 스트림인 PrintWriter 도 생성합니다.
- 보낼 메시지를 입력하고 스트림을 통해 메시지를 전달 해줍니다.
- try-catch 문을 통해 예외처리를 해주고 출력이 끝났다면 스트림을 닫아줍시다.
UDP (User Datagram Protocol)
앞서 TCP 가 마치 전화의 형식과 비슷하다고 했습니다. 반면에 UDP 는 택배 보내는 형식과 비슷합니다. 택배는 보내는 사람이 받는 사람의 사는지역이 어딘지, 어느 아파트 몇호에 사는지만 알면 택배를 보낼 수 있습니다. 또한 받는 사람은 일련의 과정 없이 보내는 사람이 택배를 보내면 그냥 받을 수 있습니다.
UDP 의 방식도 이와 비슷합니다. 보내는쪽을 Sender, 받는쪽을 receiver 라고 합니다.택배를 보내기 위해 택배상자를 싸는것처럼, 센더쪽에서는 Datagram Packet 을 이용하여 데이터를 감싸줍니다. 그리고 택배를 보내기 위해 주소를 알아야하듯, 센더는 리시버의 IP 주소와 포트번호를 알고있어야 합니다. 센더와 리시버는 우체통과 같은 역할을 하는 Datagram Socket 을 만들어주어야 하며, 이 우체통을 통해 데이터를 주고 받습니다.
Sender 용 프로그램 작성하기
try {
DatagramSocket socket = new DatagramSocket();
-- 1
Scanner scan = new Scanner(System.in);
while(true) {
System.out.print("보낼 데이터 (exit를 입력하면 종료) : ");
String msg = scan.nextLine();
if(msg.equalsIgnoreCase("exit")) break;
-- 2
byte[] bytes = msg.getBytes();
InetAddress addr = InetAddress.getByName("localhost");
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, addr, 10003);
-- 3
socket.send(packet);
-- 4
System.out.println("전송 완료");
}
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
- 우편을 보낼 우체통을 만든는 작업과 같습니다. DatagramSocket 을 이용하여 만들어 줍니다.
- 보낼 데이터를 입력하고, while 문을 빠져나갈 조건을 만들어 줍시다.
- 택배상자를 싸듯, DatagramPacket 클래스를 이용하여, 객체의 생성자 파라미터로 보낼 데이터, 데이터의 길이, 보내고자 하는 주소(IP), 포트번호를 넘겨줍시다.
- 택배를 우체통을 통해 보내듯 정보가 담긴 packet을 소켓을 통해 리시버에게로 보냅니다.
Receiver 용 프로그램 작성하기
try {
DatagramSocket socket = new DatagramSocket(10003);
-- 1
System.out.println("메시지 기다리는 중 . . .");
while(true) {
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
-- 2
socket.receive(packet);
-- 3
String msg = new String(buf);
System.out.println(msg);
-- 4
}
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
- 먼저 센더쪽에서 보낸 데이터를 받을 Datagram Socket 을 준비합시다. 여기에는 포트번호를 파라미터로 전달해주어야 합니다.
- 불행하게도 센더에서 보낸 데이터들을 받을 때 다시 packet 으로 받아주어야 합니다. 그래서 충분한 크기의 빈 packet 을 준비해줍시다.
- 우체통 즉, Socket 에 담겨진 정보들을 receive() 메서드를 통해 가져옵시다.
- buf 에 담겨진 문자열 데이터를 출력해줍시다.
'국비과정' 카테고리의 다른 글
[ANDROID 국비과정] 2023.02.08 - 안드로이드 앱 개발자 과정 (0) | 2023.09.05 |
---|---|
[ANDROID 국비과정] 2023.02.07 - 안드로이드 앱 개발자 과정 (2) | 2023.08.21 |
[ANDROID 국비과정] 2023.02.03 - 안드로이드 앱 개발자 과정 (0) | 2023.08.21 |
[ANDROID 국비과정] 2023.02.02 - 안드로이드 앱 개발자 과정 (0) | 2023.08.02 |
[ANDROID 국비과정] 2023.02.01 - 안드로이드 앱 개발자 과정 (0) | 2023.06.06 |