[JAVA]Java NIOベースのI/Oとネットワーク2
TCPブロックチャネル
転送制御プロトコル(TCP):接続向けプロトコル
ブロック:スレッドが待機中
サーバスロットチャネルとスロットチャネルの用途
ServerSocketChannel
SocketChannel
サーバスロットチャネルを作成し、接続を受け入れる
// ServerSocketChannel 객체 얻기 → 정적메서드 open() 사용
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
// 블로킹으로 설정하기(기본 설정이지만 명시적으로 설정하여 논블로킹과 구분)
ServerSocketChannel.configureBlocking(true);
// 포트에 바인딩시키기(포트 정보를 가진 InetSocketAddress 객체 매개값)
ServerSocketChannel.bind(new InetSocketAddress(5001));
// accep() 메서드로 클라이언트 연결 수락(클라이언트가 연결 요청하기 전까지 블로킹)
SocketChannel socketChannel = SeverSocketChannel.accept();
// 연결된 클라이언트의 IP와 포트 정보 얻기
// getHostName() : 클라이언트 IP 리턴
// getPort() : 클라이언트 포트 번호 리턴
// toString() : "IP : 포트번호" 형태의 문자열 리턴
InetSocketAdress socketAddress = (InetSocketAdress)socketChannel
.getRemoteAddress();
// 포트 언바인딩
serverSocketChannel.close();
コンセントチャネルの作成と接続の要求
// SocketChannel 객체 얻기 → 정적메서드 open() 사용
SocketChannel socketChannel = SocketChannel.open();
// 블로킹으로 설정하기(기본 설정이지만 명시적으로 설정하여 논블로킹과 구분)
SocketChannel.configureBlocking(true);
// 서버 연결 요청(서버 IP와 포트 정보를 가진 InetSocketAddress 객체 매개값)
// connect() 메서드는 연결이 완료될 때까지 블로킹, 완료되면 리턴
SocketChannel.connect(new InetSocketAddress("localhost",5001));
// 연결 끊기
socketChannel.close();
ソケットチャネルデータつうしん
write()メソッドを使用して文字列を送信する
// 정적 메서드 forName()으로 Charset 인스턴스 생성
// Charset : 인스턴스의 캐릭터셋과 유니코드 사이의 변환을 처리하는 클래스
Charset charset = Charset.forName("UTF-8");
// encode() 메서드를 통해 유니코드로 변환하고 ByteBuffer에 담음
ByteBuffer byteBuffer = charset.encode("Hello Server");
socketChannel.write(byteBuffer);
read()メソッドを使用して文字列を取得する
// 100개의 byte를 저장하는 ByteBuffer 생성
ByteBuffer byteBuffer = ByteBuffer.allocate();
// socketChannel에서 읽은 byte들을 buteBuffer에 저장하고 읽은 바이트 수 리턴
// 상대방이 SocketChannel의 close()를 호출하면 -1, 비정상적으로 종료되면 예외 발생
int byteCount = socketChannel.read(byteBuffer);
// 데이터 읽기 위해 위치 속성값 변경
byteBuffer.flip();
// 정적 메서드 forName()으로 Charset 인스턴스 생성
Charset charset = Charset.forName("UTF-8");
// buteBuffer안에 바이트들을 UTF-8로 변환하고 문자열로 다시 변환
String message = charset.decode(byteBuffer).toString();
スレッド並列処理
TCPブロッキングは、データの入出力が完了する前に、読み取り()および書き込み()メソッドをブロックする
👉 クライアント接続にワークスレッドを割り当てることで並列処理
🚨 パラレル処理では、複数のクライアントが同時に接続されると、サーバに複数のスレッドが作成され、サーバのパフォーマンスが低下します.
👉 スレッドプールの使用
TCP非ブロックチャネル
クローズドフィーチャー
🚨 ブロックされずに直接戻るため、accept()を繰り返し文として使用すると、コードが実行され続け、CPUが過剰に消費されます.
👉 イベントリスナーとして機能するセレクタの使用(Selector)
セレクタ
コレクタ運動原理
コレクタの作成と登録
// Selector 생성
try{
Selector selector = Selector.open();
}catch(IOException e){}
// 넌블로킹 설정
// Selector에는 SelectableChannel 하위 채널만 등록 가능
SocketChannel socketChannel = SocketChannel.open(); // 예시
SocketChannel.configureBlocking(false);
// Selector에 등록
// 첫번째 매개값은 Selector, 두번째 매개값은 채널의 작업
SelectionKey selectionKey = socketChannel.register(selector
, SelectionKey.OP_READ);
2番目のパラメータとして使用できる特定の操作タイプの選択キー定数🚨 同じSocketChannelを使用して2つ以上の操作タイプを登録することはできません.
選択したキーセット
select()が戻る場合
チャネルの操作タイプを変更します。
// selectionKey 작업 유형 변경
selectionKey.interstOps(SelectionKey.OP_WRITE);
// 블로킹되어 있던 select() 리턴
selector.wakeup();
// select() 다시 실행
int keyCount = selector.select();
// 값이 1 이상일 경우 selectedKeys() 작업 처리 준비된 Set<SelectionKey>를 얻음
if(keyCount > 0){
Set<SelectionKey> selectedKey = selector.selectedKeys();
}
チャネルタスクの処理
タスクを処理するには、ワークスレッドが選択キーがどのタイプのタスクであるかを決定する必要があります.
// 채널 객체를 얻으려면 SelectionKey의 channel() 메소드를 사용
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
// 채널 객체 이외의 객체 첨부하기
Client client = new Client(socketChannel);
SelectionKey selectionKey = socketChannel.register(selector, SelectionKey.OP_READ);
selectionKey.attach(client);
// 첨부된 객체 얻기
if(selectionKey.isReadable()){
Client client = (Client)selectionKey.attachment();
}
TCP非同期チャネル
ひどうきチャネルとくせい
read()メソッドの例
非同期チャネルグループ
同じスレッドプールを共有する非同期チャネルグループ
非同期チャネルグループの作成
非同期チャネルグループを終了
新しい非同期チャネルを含めるには、ShutdownChannel Group Exception
ベースチャネルグループ
UDPチャネル
送信者の作成
// DatagramChannel 생성을 위해 open() 호출
// open()은 ProtocolFamilydml 인터페이스 타입의 매개값을 가짐
// 구현 객체로 StandardProtocolFamily 열거 상수 사용
// IPv4와 IPv6을 구분하는 역할
DatagramChannel datagramChannel = DatagramChannel.open(StandardProtocolFamily.INET);
// send() 메소드를 이용해 데이터 보내기
// 첫번째 매개값은 보낼 데이터, 두번째는 수신자 정보를 가진 SocketAddress(추상 클래스)
// 하위 클래스인 InetSocketAddress 생성해서 대입
int byteeCount = datagramChannel.send(byteBuffer, new InetSocketAddress("localhost", 5001));
// 닫기
datagramChannel.close();
受信者の作成
// DatagramChannel 생성을 위해 open() 호출
// bind()를 호출해서 포트와 바인딩
DatagramChannel datagramChannel = DatagramChannel.open(StandardProtocolFamily.INET);
datagramChannel.bind(new InetSocketAddress(5001));
// receive() 메소드를 이용해 데이터 받기
// 데이터 받기 전까지는 블로킹 받으면 리턴
SocketAddress socketAddress = datagramChannel.receive(ByteBuffer dst);
// 작업 스레드 종료
// 작업 스레드의 interrup() 호출로 예외 발생
// datagramChannel에 close()을 호출시켜 예외 발생
// 예외 처리코드에서 작업 스레드를 종료 시킴
datagramChannel.close();
Reference
この問題について([JAVA]Java NIOベースのI/Oとネットワーク2), 我々は、より多くの情報をここで見つけました https://velog.io/@3hee_11/JAVA-이것이-자바다-NIO-기반-입출력-및-네트워킹2テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol