네트워킹에 대해 말할 때 OSI 모델을 언급하지 않을 수 없습니다.

이 모델의 관점에서 오늘날 우리는 전송 계층(4)에 가장 관심이 있습니다.

이것은 "지점 A에서 지점 B로" 이동하는 데이터로 작업하는 수준입니다. 전송 계층의 주요 작업은 올바른 순서를 유지하면서 메시지가 목적지로 전달되도록 하는 것입니다. 가장 일반적인 두 가지 전송 계층 프로토콜은 TCP와 UDP입니다. 그들은 개념적으로 다른 방식으로 작동하지만 각각은 특정 문제를 해결할 수 있는 고유한 장점이 있습니다.

먼저 TCP의 작동 방식을 살펴보겠습니다.

TCP(전송 제어 프로토콜)는 데이터를 교환하기 전에 호스트 간의 연결이 설정되도록 하는 네트워크 프로토콜입니다.

다른 데이터 패킷을 보낼 때마다 이전 패킷이 수신되었는지 확인해야 하기 때문에 이것은 매우 안정적인 프로토콜입니다.

전송된 패킷은 순서대로 정렬되며, 특정 패킷에 문제가 있는 경우(즉, 수신자가 패킷이 도착했는지 확인하지 않은 경우) 패킷을 다시 전송합니다. 결과적으로 엄격한 모니터링과 올바른 주문을 보장하는 데 더 많은 시간이 필요하기 때문에 전송 속도가 상대적으로 낮습니다.

여기서 "형제"인 UDP 프로토콜이 등장합니다. TCP와 달리 UDP는 각 패킷의 순서와 상태에 대해 별로 신경 쓰지 않습니다. 배송 확인 없이 단순히 데이터를 보냅니다. 또한 연결을 설정하지 않으며 어떤 식으로든 연결 상태에 의존하지 않습니다.

그 목적은 단순히 데이터를 주소로 보내는 것입니다. 그리고 이것은 단순히 데이터 조각을 잃을 수 있기 때문에 프로토콜의 주요 단점인 낮은 신뢰성을 야기합니다. 또한 수신자는 데이터가 잘못된 순서로 도착할 수 있다는 사실에 대비해야 합니다. 즉, 프로토콜이 데이터 전송으로 제한된다는 사실로 인해 프로토콜은 더 높은 전송 속도라는 이점도 있습니다.

데이터 자체가 전송되는 방식에도 차이가 있습니다. TCP에서는 데이터가 스트리밍됩니다. 즉, 데이터에 경계가 없습니다. UDP에서 데이터는 데이터그램으로 전송되고 경계가 있으며 수신자는 데이터의 무결성을 확인하지만 메시지가 성공적으로 수신된 경우에만 확인합니다.

요약하자면:

TCP는 데이터 손실을 방지하는 안정적이고 정확한 프로토콜입니다. 메시지는 항상 최대 정확도로 전달되거나 전혀 전달되지 않습니다. 들어오는 데이터는 이미 주문되므로 수신자는 데이터 주문을 위한 논리가 필요하지 않습니다. UDP는 신뢰할 수는 없지만 더 빠른 데이터 전송 프로토콜입니다. 송수신 당사자는 이 프로토콜을 사용하기 위해 몇 가지 추가 로직이 필요합니다. 그러나 네트워크를 통해 실행되는 컴퓨터 게임이나 모바일 게임의 예를 사용하여 어떻게 작동하는지 살펴보겠습니다. 우리는 더 이상 5초 전에 도착했어야 하는 것에 대해 신경 쓰지 않을 수 있으며, 패킷이 제 시간에 도착하지 않으면 몇 개의 패킷을 건너뛸 수 있습니다. 게임이 지연될 수 있지만 여전히 플레이할 수 있습니다!

Java에서는 UDP를 통해 전송되는 데이터그램으로 작업하기 위해 DatagramSocketDatagramPacket 클래스의 개체를 사용합니다.

데이터를 교환하기 위해 발신자와 수신자는 데이터그램 소켓, 즉 DatagramSocket 클래스의 인스턴스를 만듭니다. 이 클래스에는 여러 생성자가 있습니다. 그들 사이의 차이점은 생성된 소켓이 연결되는 위치입니다.

데이터그램소켓() 로컬 시스템에서 사용 가능한 모든 포트에 연결
DatagramSocket(int 포트) 로컬 시스템의 지정된 포트에 연결합니다.
DatagramSocket(int 포트, InetAddress 주소) 로컬 시스템(addr)의 주소에서 지정된 포트에 연결합니다.

이 클래스에는 소켓 매개변수에 액세스하고 관리하기 위한 많은 메소드(나중에 살펴볼 것임)와 데이터그램을 수신 및 전송하기 위한 메소드가 포함되어 있습니다.

보내기(DatagramPacket 팩) 패킷으로 압축된 데이터그램을 보냅니다.
수신(DatagramPacket 팩) 패킷으로 묶인 데이터그램 수신

DatagramPacket 은 데이터그램 패키지를 나타내는 클래스입니다. 데이터그램 패킷은 연결 없는 패킷 전달 서비스를 구현하는 데 사용됩니다. 각 메시지는 해당 패킷에 포함된 정보만을 기반으로 한 시스템에서 다른 시스템으로 라우팅됩니다. 한 시스템에서 다른 시스템으로 전송된 여러 패킷은 다르게 라우팅될 수 있으며 임의의 순서로 도착할 수 있습니다. 패킷 전달이 보장되지 않습니다.

생성자:

DatagramPacket(byte[] buf, int 길이) 길이가 length 인 패킷을 수락하는 DatagramPacket을 만듭니다 .
DatagramPacket(byte[] buf, int 길이, InetAddress 주소, int 포트) 지정된 호스트의 지정된 포트 번호로 길이 길이 의 패킷을 보내는 데이터그램 패킷을 생성합니다 .
DatagramPacket(byte[] buf, int 오프셋, int 길이) 버퍼에 오프셋을 지정하여 length 길이 의 패킷을 수락하는 DatagramPacket 을 만듭니다 .
DatagramPacket(byte[] buf, int 오프셋, int 길이, InetAddress 주소, int 포트) 지정된 호스트의 지정된 포트 번호로 오프셋 오프셋이 있는 길이 길이 의 패킷을 보내는 데이터그램 패킷을 생성합니다 .
DatagramPacket(byte[] buf, int 오프셋, int 길이, SocketAddress 주소) 지정된 호스트의 지정된 포트 번호로 오프셋 오프셋이 있는 길이 길이 의 패킷을 보내는 데이터그램 패킷을 생성합니다 .
DatagramPacket(byte[] buf, int 길이, SocketAddress 주소) 지정된 호스트의 지정된 포트 번호로 길이 길이 의 패킷을 보내는 데이터그램 패킷을 생성합니다 .

UDP 접근 방식은 연결을 설정하지 않습니다. 패킷은 수신자가 기대하고 있다는 희망에 따라 전송됩니다. 그러나 DatagramSocket 클래스의 connect(InetAddress addr, int port) 메서드를 사용하여 연결을 설정할 수 있습니다 .

데이터그램을 보내거나 받기 위해 주소와 포트를 기반으로 호스트와 단방향 연결이 설정됩니다. 연결은 disconnect() 메서드를 사용하여 종료할 수 있습니다.

DatagramSocket을 기반으로 데이터를 수신하는 서버 코드를 작성해 보겠습니다 .


import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

class Recipient {

   public static void main(String[] args) {
       try {
           DatagramSocket ds = new DatagramSocket(1050);

           while (true) {
               DatagramPacket pack = new DatagramPacket(new byte[5], 5);
               ds.receive(pack);
               System.out.println(new String(pack.getData()));
           }
       } catch (IOException e) {
           e.printStackTrace();
       }
   }
}

포트 1050에서 수신할 DatagramSocket 객체를 만듭니다. 메시지를 받으면 콘솔에 출력합니다. "Hello"라는 단어를 전송할 것이므로 버퍼 크기를 5바이트로 제한합니다.

이제 보낸 사람 클래스를 만듭니다.


import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

class Sender {
   private String host;
   private int port;

   Sender(String host, int port) {
       this.host = host;
       this.port = port;
   }

   private void sendMessage(String mes) {
       try {
           byte[] data = mes.getBytes();
           InetAddress address = InetAddress.getByName(host);
           DatagramPacket pack = new DatagramPacket(data, data.length, address, port);
           DatagramSocket ds = new DatagramSocket();
           ds.send(pack);
           ds.close();
       } catch (IOException e) {
           System.err.println(e);
       }
   }

   public static void main(String[] args) {
   Sender sender = new Sender("localhost", 1050);
   String message = "Hello";

   Timer timer = new Timer();
   timer.scheduleAtFixedRate(new TimerTask() {
       @Override
       public void run() {
           sender.sendMessage(message);
       }
   }, 1000, 1000);
}

}

sendMessage 메서드 에서 DatagramPacketDatagramSocket 을 만들고 메시지를 보냅니다. close () 메서드는 메시지가 전송된 후 DatagramSocket을 닫는 데 사용됩니다 .

받는 사람의 콘솔은 매초 발신자가 보낸 들어오는 "Hello" 메시지를 표시합니다. 이것은 우리의 통신이 모두 올바르게 작동하고 있음을 의미합니다.