2016년 7월 22일 금요일

JDK 1.4 튜토리얼 - 2장 NIO- 논블록킹-Polling

2.3 넌블록킹 I/O

JDK1.4 이전에는 java.io에서는 non-blocking(상세) 을 지원하지 않음
특징
  • 작업 종료 후 응답이 돌아오기 전에 다음 작업 수행할 수 있음
  • 많은 수의 I/O 커넥션을 관리시 오버헤드를 감소 시킴(**)
  • C/S 서버 환경에서 좋은 성능을 발휘 함
  • Non-Blocking 기법은
    • Polling 방식 - 주기적으로 확인
    • Multiplexing 방식 - select를 사용하는 event 방식
다중 쓰레드를 사용함(Blocking 방식)
  • 단점
    • 많은 쓰레드 자원을 소비 한다.
  • 장점
    • 구조를 단순화 할 수 있음
  • 만약 다중 쓰레드를 단일 쓰레드 방식으로 변경하면 특정 통신에 이상 발생하면 나머지 모든 멈추는 현상이 발생 하게 된다.
Polling(폴링)
  • 단점
    • 폴링 대기시간이 존재하면 결국 대기 시간을 줄이게 되면 부하가 상승함.
    • 매우 짧고 높은 응답 성능을 요구하는 서버에서는 사용이 적절하지 않음

package ns.jdk14;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.*;

public class PollingChatServer implements Runnable{
   private static final int sleepTime = 100; //SLEEP_TIME
   private int port;   //포트번호
   private Vector<Socket> sockets = new Vector<>();
   private Set<Socket> closedSockets = new HashSet<>();

   public PollingChatServer(int port) {
       this.port = port;
       Thread t = new Thread(this,"PollingChatServer");
       t.start();
   }

   @Override
   public void run() {
       try{
           //1) 논블록킹 서버 소켓 OPEN
           ServerSocketChannel ssc = ServerSocketChannel.open();
           ssc.configureBlocking(false);
           ServerSocket ss = ssc.socket();
           InetSocketAddress isa = new InetSocketAddress(port);
           ss.bind(isa);

           ByteBuffer buffer = ByteBuffer.allocate(4096);
           System.out.println("Listening on port "+port);
           while(true){
               //2) 서버 소켓에 새로운 연결이 들어옴
               SocketChannel sc = ssc.accept();
               //연결이 있는 경우에는 not null 이고 null 이면 없는 경우 이다.
               if(sc != null){
                   Socket newSocket = sc.socket();
                   System.out.println("Connection from "+newSocket);
                   //논블록킹으로 설정    
                   newSocket.getChannel().configureBlocking(false);
                   sockets.addElement(newSocket);
               }
               //3) 클라이언트 소켓중의 하나로 데이터가 읽혀짐
               for(Enumeration<Socket> e = sockets.elements();
                   e.hasMoreElements();){
                   Socket socket = null;
                   try{
                       socket = e.nextElement();
                       SocketChannel sch = socket.getChannel();
                       buffer.clear();
                       sch.read(buffer);
                       //Data가 있는 경우
                       if(buffer.position() > 0){
                           buffer.flip();
                           System.out.println("Read "+buffer.limit()
                                   +" bytes from "+sch.socket());
                           sendTOAll(buffer);
                       }

                   }catch(IOException ie){
                       closedSockets.add(socket);
                   }
               }

               removeClosedSockets();
               try {
                   Thread.sleep(sleepTime);
               }catch(InterruptedException ie){}
           }
       }catch(IOException e){e.printStackTrace();}
   }
   /**
    * 4) Data 클라이언트 소켓에
    * @param bb
    */
   private void sendTOAll(ByteBuffer bb){
       for(Enumeration<Socket> e = sockets.elements();
           e.hasMoreElements();){
           Socket socket = null;

           try{
               socket = e.nextElement();
               SocketChannel sc = socket.getChannel();
               //버퍼의 포지션을 시작 위치로 변경함.
               bb.rewind();
               //보낼것이 있는 경우
               while(bb.remaining() > 0){
                   sc.write(bb);
               }
           }catch(IOException ie){
               closedSockets.add(socket);
           }
       }
   }
   /**
    * 5) 연결 종료된 소켓 제거
    */
   private void removeClosedSockets(){
       for(Iterator<Socket> it=closedSockets.iterator();it.hasNext();){
           Socket socket = it.next();
           sockets.remove(socket);
           System.out.println("Removed "+socket);
       }
       closedSockets.clear();
   }
   public static void main(String[] args) {
       //Integer.parseInt(args[0]);
       int port = 5555;
       new PollingChatServer(port);
   }
}

출처 : 인포북 JDK 1.4 Tutorial

2016년 7월 21일 목요일

JDK 1.4 튜토리얼 - 2장 NetworkInterface

2.4 네트워크 인터페이스

java.net.NetworkInterface
  • 네트워크 통신의 인터페이스를 표현하는 OS 레벨의 객체에 대한 접근 기능을 제공
  • NIC 정보를 제공
  • InetAddress 주소를 제공
  • NetworkInterface목록 구하기
    • NetworkInterface.getNetworkInterface()
  • NetworkInterface 구하기
    • getByInetAddress() : InetAddress 주소를 사용
    • getByName() : 인터페이스 이름로 (lo, eth0)
    • getByIndex() : 인터페이스 Index
  • InetAddress 주소 리스트 구하기
    • networkInterface.getInetAddresses()
    • 대부분 단일 주소를 가지고 있음

디폴트 인터페이스
  • 일반적으로 IP 통신에 위한 사용하는 인터페이스
  • netstat -rn 명령어 결과에서 네트워크 0.0.0.0 , NetMask 0.0.0.0 에 해당한다.
  • 서버 소켓에서는 포트만 주어주는 경우에 해당한다. 특정 인터페이스 참고 없이 동작할 수 있다는 의미
  • 0.0.0.0 와 localhost(127.0.0.1) 분명한 차이가 있다.
    • 0.0.0.0은 디폴트 인터페이스 이다.
    • localhost : loop back 주소임

특정 주소에 대해서 Listen 하기

  • 디폴트 주소에 대해 리스닝하기
    • 포트만 주어 지는 경우
    • 디폴트 주소 (0.0.0.0) 이며, 실제 주소가 아님 이 주소를 통하여 리스닝 하면 모든 주소에 리스닝 하는 것 이다
    • 간혹 특정 네트워크 API 에서 직접 주소를 지정하는 경우가 있는데. localhost 대신 반드시 0.0.0.0을 사용해야 한다.
출처 : 인포북 JDK 1.4 Tutorial