자바

자바 NIO UDP 채널 발신자와 수신자와 통신

알통몬_ 2017. 5. 5. 12:34
반응형


안녕하세요 알통몬입니다.

공감 및 댓글은 포스팅 하는데 아주아주 큰 힘이 됩니다!!

포스팅 내용이 찾아주신 분들께 도움이 되길 바라며

더 깔끔하고 좋은 포스팅을 만들어 나가겠습니다^^

 


UDP 채널 :

NIO에서 UDP 채널은 DatagramChannel 입니다. DatagramChannel도 TCP 채널과 마찬가지로

블로킹 방식과 넌 블로킹 방식이 있습니다


발신자 :

DatagramChannel 을 생성하기 위해서는 open()을 호출해야 합니다.

open() 은 ProtocolPamily 인스턴스 타입의 매개값을 가집니다.

=> 이 객체의 역할은 IPv4 와 IPv6를 구분하는 역할을 합니다.

구현 객체는 StandardProtocalFamily 열거 상수를 사용합니다.

DatagramChannel datagramChannel = DatagramChannel.open(StandardProtocolFamily.INET);

DatagramChannel을 이용해 데이터를 보내려면 send()메서드 사용.

첫 매개값은 보낼 데이터를 가지는 ByteBuffer이고, 두번 째 매개값은 IP와 포트 정보를 가지고 있는

SocketAddress. 

SocketAddress는 추상 클래스 => 하위 클래스인 InetSocketChannel객체를 생성하고 대입.

send()의 리턴 값은 실제 보낸 바이트 수

ex)

 int byteCount = datagramChannel.send(byteBuffer, new InetSocketAddress("localhost", 5001));

더이상 보낼 데이터가 없다면 DatagramChannel을 닫기 위해 close()를 사용

datagramChannel.close();

import java.net.InetSocketAddress;

import java.net.StandardProtocolFamily;

import java.nio.ByteBuffer;

import java.nio.channels.DatagramChannel;

import java.nio.charset.Charset;


public class UdpSendExample {

 public static void main(String[] args) throws Exception {

  DatagramChannel datagramChannel = DatagramChannel.open(StandardProtocolFamily.INET);

  

  System.out.println("[발신 시작]");

  

  for(int i=1; i<3; i++) {

   String data = "메시지" + i;

   Charset charset = Charset.forName("UTF-8");

   ByteBuffer byteBuffer = charset.encode(data);

   

   int byteCount = datagramChannel.send(

    byteBuffer,  

    new InetSocketAddress("localhost", 5001)

   ); // 데이터 보내기

   System.out.println("[보낸 바이트 수] " + byteCount + " bytes");

  }

  

  System.out.println("[발신 종료]");

  

  datagramChannel.close();

 }

 

}


수신자 :
DatagramChannel 을 이용해 데이터를 받기 위해서는 bind() 를 호출해 먼저 포트와 바인딩을 해야합니다.

DatagramChannel datagramChannel = DatagramChannel.open(StandardProtocalFamily.INET);


포트와 바인딩 후 recieve() 로 데이터를 받을 수 있습니다.

매개 값을 받은 데이터를 저장할 ByteBuffer 이고 리턴 타입은 원격 클라이언트의 IP와 포트 정보를

가지고 있는 SocketAddress 이고 실제는 InetSocketAddress 가 리턴됩니다.

SockeAddress socketAddress = datagramChannel.receive(ByteBuffer dst);


데이터를 받기 전까지 receive() 는 블로킹이 되고, 데이터를 받으면 리턴됩니다.

수신자는 항상 데이터를 받을 준비를 해야합니다.

=> 작업 스레드를 생성해서 receive()를 반복적으로 호출해야 합니다.

작업 스레드 종료 방법

- receive()가 블로킹되어 있는 상태에서 작업 스레드의 interrupt()를 호출하여 ClosedInterruptException 예외를 발생시키거나 

- DatagramChannel의 close()를 호출하여 AsynchronousCloseException예외를 발생 시키고

그 후 예외 처리 코드에서 작업 스레드를 종료시키면 됩니다.

datagramChannel.close();

import java.net.InetSocketAddress;

import java.net.SocketAddress;

import java.net.StandardProtocolFamily;

import java.nio.ByteBuffer;

import java.nio.channels.DatagramChannel;

import java.nio.charset.Charset;


public class UdpReceiveExample extends Thread {

 public static void main(String[] args) throws Exception {

  DatagramChannel datagramChannel = DatagramChannel.open(StandardProtocolFamily.INET);

  datagramChannel.bind(new InetSocketAddress(5001));

  

  Thread thread = new Thread() { // 스레드 생성

   @Override

   public void run() {

    System.out.println("[수신 시작]");

    try {

     while(true) {

      ByteBuffer byteBuffer = ByteBuffer.allocateDirect(100);

      SocketAddress socketAddress = datagramChannel.receive(byteBuffer); // 데이터 받기

      byteBuffer.flip();

      

      Charset charset = Charset.forName("UTF-8");

      String data = charset.decode(byteBuffer).toString();

      System.out.println("[받은 내용: "  + socketAddress.toString() + "] " + data);

     }

    } catch (Exception e) {

     System.out.println("[수신 종료]");

    }

   }   

  };

  thread.start();

  

  Thread.sleep(10000);

  datagramChannel.close();

 }

 

}





반응형