네트워크 통신(2)
날짜: 2021년 6월 15일
학습목표
지난 포스팅에서 자바를 통한 네트워크 통신 중 TCP통신 방식에 대해 알아보았다. 이번 포스팅에서는 UDP 통신에 대해서 직접 구현해보자.
- UDP 프로그래밍
UDP 통신을 위해 알아야 하는 Datagram 클래스
이번 포스팅에서는 UDP 통신을 하는 법을 알아보자. UDP는 TCP와 달리 데이터가 제대로 전달되었음을 보장하지 않는다. 따라서 유실되어도 무관한 데이터들에 한해서만 사용하는게 좋겠다.
UDP통신을 하려면 TCP와 마찬가지로 데이터를 주고 받기 위한 클래스가 필요하다. 여기서 TCP와는 다르게 클래스 하나에서 주고 받는 역할을 모두 수행할 수있다.
바로 Datagram 클래스이다. TCP에서는 스트림을 사용해 데이터를 주고 받았으나, UDP통신에서는 DatagramPacket 이라는 클래스를 사용한다.
This class represents a socket for sending and receiving datagram packets.
자바 API문서에 따르면 datagram packet을 송수신 하는 소켓이라 적혀있다!
Datagram클래스
먼저 Datagram클래스의 생성자를 알아보자. Socket클래스와 비슷한 면이 보일것이다!
일반적인 소켓과 마찬가지로 사용이 끝나면 close()를 호출해야한다.
데이터를 받기위해 대기할 때는 receive()메소드를 사용하고, 데이터를 보낼 때에는 send() 메소드를 사용한다.
크게 어렵지 않은 메소다. 이전에 공부했던 소켓 클래스의 메소드와 비슷하다. 그럼 매개변수로 사용되는 DatagramPacket 클래스에 대해서도 알아보자.
Datagram packets are used to implement a connectionless packet delivery service
연결점 없는?,, 패킷 전달 서비스를 구현하기 위해 사용된다고 한다. 연결점이 없다는게 뭘까?..
그럼 DatagramPacket 클래스의 생성자를 알아보도록 하자.
생성자의 매개변수에서 byte의 배열은 전송되는 데이터이다. offset은 전송되는 byte 배열의 첫 위치이다. 만약 offset이 1이며느 배열의 0번째가 아닌 1번째 부터 데이터를 전송한다.
DatagramPacket의 메소드 중 반드시 알아야하는 메소드는 2가지가 있다.
간단한 UDP통신을 실습해보자!
자, 그럼 위에서 알아본 생성자와 메소드들로 간단하게 UDP통신을 하는 실습을 진행해보자!
- 서버
package network;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class DatagramServerSample {
public static void main(String[] args) {
DatagramServerSample sample = new DatagramServerSample();
sample.startServer();
}
public void startServer() {
try(DatagramSocket server = new DatagramSocket(9999)){
int bufferLength = 256;
byte[] buffer = new byte[bufferLength];
DatagramPacket packet= new DatagramPacket(buffer, bufferLength);
while(true) {
System.out.println("Server:Waiting for requset.");
server.receive(packet);
int dataLength = packet.getLength();
System.out.println("Server:received. Data lenght = " +dataLength);
String data = new String(packet.getData(),0,dataLength);
System.out.println("Received Data : " + data);
if(data.equals("EXIT")) {
System.out.println("Stop DatagraServer");
break;
}
System.out.println("---------------------------");
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
코드에서 주요 메소드 부분을 보며 이해해보도록하겠다.
DatagramSocket server = new DatagramSocket(9999)
포트번호 9999인 DatagramSockey 객체를 생성, 대기한다.
DatagramPacket packet= new DatagramPacket(buffer, bufferLength);
데이터를 받기위한 DatagramPacket 객체를 생성한다. 여기서 생성된 객체는 length가 256까지인 데이터를 받을 수 있다. TCP에서는 스트림을 통해 데이터를 송수신 했으나, UDP에서는 DatagramPacket을 통해 송수신 함을 잊지 말자!
server.receive(packet);
데이터를 받기위해 대기하고 있다가, 데이터가 들어오면 packet 객체에 데이터를 담는다.
TCP통신의 accept() 메소드와 비슷한 방식이다.
int dataLength = packet.getLength();
전송 받은 데이터의 크기를 확인한다.
String data = new String(packet.getData(),0,dataLength);
전송받은 byte[] 형의 데이터를 문자열로 변환한다. 왜 packet.getData().toString()을 하지 않을까?
byte[]의 toString()은 Object에 정의된 로직으로 값이 아닌, 주소값을 반환하기 때문이다.
- 클라이언트
package network;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.util.Date;
public class DatagramClientSample {
public static void main(String[] args) {
DatagramClientSample sample = new DatagramClientSample();
sample.sendDatagramSmaple();
}
public void sendDatagramSmaple() {
for(int i=0; i<3; i++) {
sendDatagramData("I liekd UDP " + new Date());
}
sendDatagramData("EXIT");
}
public void sendDatagramData(String data) {
try(DatagramSocket client = new DatagramSocket()){
InetAddress address = Inet4Address.getByName("127.0.0.1");
byte[] buffer = data.getBytes();
DatagramPacket packet = new DatagramPacket(buffer, 0,buffer.length, address, 9999);
client.send(packet);
System.out.println("Client: Sent data");
Thread.sleep(1000);
} catch (IOException | InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
서버사이드와 마찬가지로 클라이언트 사이드도 코드를 확인해보자!
DatagramSocket client = new DatagramSocket()
DatagramSocket 객체를 생성, 대기한다.
InetAddress address = Inet4Address.getByName("127.0.0.1");
InetAddress 는 Autocloseable()을 구현하지 않아 try() 구문에 들어갈 수 없다.
InetAddress 클래스를 사용해 데이터를 받을 서버의 IP를 설정한다.
DatagramPacket packet = new DatagramPacket(buffer, 0,buffer.length, address, 9999);
DatagramPacket 역시 Autocloseable을 구현하지 않아 try() 구분에 들어갈 수 없다.
데이터를 전송하기 위해 DatagramPacket 객체를 생성한다. 생성자에 주소와 port를 지정하면 데이터를 받기위한 객체가 아니라, 전송하기 위한 객체가 된다!
client.send(packet);
데이터를 전송한다.
결과 콘솔
서버 콘솔
Server:Waiting for requset. Server:received. Data lenght = 40 Received Data : I liekd UDP Tue Jun 15 15:09:14 KST 2021 --------------------------- Server:Waiting for requset. Server:received. Data lenght = 40 Received Data : I liekd UDP Tue Jun 15 15:09:15 KST 2021 --------------------------- Server:Waiting for requset. Server:received. Data lenght = 40 Received Data : I liekd UDP Tue Jun 15 15:09:16 KST 2021 --------------------------- Server:Waiting for requset. Server:received. Data lenght = 4 Received Data : EXIT Stop DatagraServer
클라이언트 콘솔
Client: Sent data Client: Sent data Client: Sent data Client: Sent data
잠깐! 여기서 한가지만 더 확인해보자. UDP는 TCP와 다르게 데이터전송을 보장하지 않는다고 했다. 그럼 서버없이 클라이언트만 실행되면 어떻게 될까?? TCP통신에서는 나타날수 있는 예외중 하나로 서버가 없이 클라이언트만 구동될때 예외가 발생함을 배웠었다.
결과
Client: Sent data Client: Sent data Client: Sent data Client: Sent data
아무런 오류없이 데이터를 전송한다.
자바에서 웹 페이지 요청을 하려면 어떻게 해야할까?
자바 API가 제공하는 URL클래스를 사용하면 아주 간단한 요청은 처리할수 있지만, 운영 시스템에서는 이 클래스를 지양할것을 권고한다. 이 클래스에서는 연결에 대한 상세한 설정을 할 수가 없기 때문이다. 그래서 일반적으로 Apache의 Http Components를 많이 사용한다.
Feedback
간단한 예제들만 있어서 그런건지, 이해가 크게 안되는건 없었다.
알게된 점
- UDP 프로그래밍
알아야할 점
- OSI 7 계층
- 소켓연결에 문제가 있을 경우 Timeout관련 메소드는 꼭 확인해보자! → 실제 운영 시스템에서는 매우 중요하기 때문이다.
References
자바의신 VOL2
'프로그래밍 > Java' 카테고리의 다른 글
Spring VS Spring Boot 의 배포차이 (0) | 2021.07.03 |
---|---|
Non-Blocking,Blocking VS Async,Sync (0) | 2021.06.19 |
네트워크 통신(1) (0) | 2021.06.15 |
Buffer (0) | 2021.06.14 |
NIO(3) (0) | 2021.06.14 |