본문 바로가기
👨‍🏫Study/JAVA

[JAVA] 19. NIO 기반 입출력 및 네트워킹(4)

by 코푸는 개발자 2022. 4. 6.
728x90

1. TCP 블로킹 채널

  • NIO에서 TCP 네트워크 통신을 위해 사용하는 채널 :                                                                  java.nio.channels.ServerSocketChannel과 java.nio.channels.SocketChannel
  • ServerSocketChannel과 SocketChannel은 블로킹과 넌블로킹 방식을 모두 지원.
  • 사용 방법은 IO와 큰 차이점이 없다.

 

 

 

TCP 블로킹 채널의 서버소켓 채널 생성과 연결 수락

  • 서버를 개발하려면 ServerSocketChannel 객체를 얻어야 한다.

 

ServerSocketChannel  생성 방법

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); // ServerSocketChannel 객체 생성
serverSocketChannel.configureBlocking(true);   //블로킹 방식 사용
serverSocketChannel.bind(new InetSocketAddress(5001)); // 바인딩 포트 5001로 설정

 

  • 포트 바인딩이 끝나면 ServerSocketChannel은 클라이언트 연결 수락을 위해 accept()메소드를 실행해야 한다.
    • accept()메소드는 클라이언트가 연결 요청 전까지는 블로킹되므로 UI및 이벤트 처리 스레드에서 사용하면 안됨

 

ServerSocketChannel의 accept() 생성 방법

SocketChannel socketChannel = serverSocketChannel.accept();// 클라이언트와 통신할 SocketChannel 객체를 리턴함

 

  • 연결된 클라이언트 IP와 포트 정보를 알고 싶다면 SocketChannel의 getRemoteAddress()메소드를 호출해서 SocketAddress를 얻음
InetSocketAddress socketAddress = (InetSocketAddress)socketChannel.getRemoteAddress();

 

 

InetSocketAddress에는 다음과 같은 IP와 포트 정보를 리턴함

 

 

 

  • 더 이상 클라이언트와 연락 수락할 필요 없다면 ServerSocketChannel의 close()메소드를 호출
serverSocketChannel.close();

 

 

TCP 블로킹 채널의 소켓 채널 생성과 연결 요청

  • 클라이언트가 서버에 연결 요청을 할 때에는 java.nio.channels.SocketChannel을 이용

 

SocketChannel 생성 방법

SocketChannel socketChannel = SocketChannel.open(); 
socketChannel.configureBlocking(true);   // 블로킹 방식으로 동작시키기 위해서 호출
socketChannel.connect(new InetSocketAddress("localhost",5001));
                            //InetSocketAddress객체에 연결 요청할 서버의 IP와 포트번호를 매개값으로 넣는다.
  • connect()메소드는 서버와 연결될 때까지 블로킹되므로 UI및 이벤트를 처리하는 스레드에선 호출하지 않음

 

  • 연결을 끊고 싶다면 SocketChannel의 close()메소드 호출
SocketChannel.close();

 

TCP 블로킹 채널의 소켓 채널 데이터 통신

  • 서버와 클라이언트 양쪽의 SocketChannel객체의 read(), write()메소드를 호출해서 데이터 통신을 할 수 있다.
  • read(), write()메소드 모두 버퍼를 이용하기 때문에 버퍼를 읽고 쓰는 작업이 필요.

 

ex. SocketChannel의 write()메소드를 이용하여 문자열 보내기

Charset charset = Charset.forName("UTF-8");
ByteBuffer byteBuffer = charset.encode("Hello Server");
socketChannel.write(byteBuffer);

 

 

 

ex. SocketChannel의 read()메소르를 이용하여 문자열 받기

ByteBuffer byteBuffer = ByteBuffer.allocate(100):
int byteCount = socketChannel.read(byteBuffer);
byteBuffer.filp(); // 사용 이유: 처음부터 받기 위해서
Charset charset = Charset.forName("UTF-8");
String message = charset.decode(byteBuffer).toString();

 

 

  • read() 메소드를 호출하면 상대방이 데이터를 보내기 전까지 블로킹되는데, read()메소드 블로킹 해제되고, 리턴되는 경우는 세가지가 있다.

 

 

스레드 병렬 처리

 

  • read()와 write()메소드로 인한 블로킹때문에 스레드를 새로 생성하여 처리 작업을 해주어야 한다. 
    • 그러나 모든 작업에 스레드를 하나씩 할당해서 병렬 처리 시 작업 수가 많아지면 서버가 다운되는 상황이 일어날 수 있다.

 

※ 프로그램의 성능을 위해서 스레드 풀을 이용하여 작업 스레드 수를 한정 시켜주어 해결 가능한다. 

728x90

댓글