내가 하고 싶은거 소켓에 대한 계략적 설명과 사용
다음에 자바로 소켓 프로그래밍하는 법
프록시 패턴을 하던 중에 RMI를 이용하면 원격 프록시를 만들 수 있다고 하더라. 그래서 찾다가 찾다가 보니 결국 모든 것은 하나로 이어진다는 것을 알았다. 결론부터 말하면 RMI도 결국 Socket기반이다. 그래서 Socket 프로그래밍을 할줄 알면 RMI는 쉬울 수 있다는 결론이 났다. 그래서 계략적으로 가지고 놀아볼 예정이다.
선행지식
소켓이란
구성요소
소켓 특징
흐름
구현 방법
서버 | 클라이언트 | |
포트지정 bind | O | X |
수신 대기 listen | O | X |
지정된 포트에 대해 원격 장비의 연결 받기 accept | O | X |
원격 장비에 연결 connect | O | O |
데이터보내기 send | O | O |
데이터 받기 recv | O | O |
연결 닫기 close | O | O |
유용한 메서드
유용한 사용방법
알아 두면 좋음
선행 지식
운영체제
사용자가 자원의 관리나 할당에 신경을 쓰지 않고 처리할 수 있는 것들을 제공해서 편리하게 사용자들이 쓸 수 있게 해주는 것
운영체제의 모드
사용자 모드
사용하는 대부분의 프로그램들이 동작하는 모드
커널 모드
운영체제 내부의 커널이 관리하는 프로세스의 모드
즉, 애플리케이션 → 사용자 모드 운영체제 요청 받음 → 커널모드 운영체제 요청 받음 → 실제 하드웨어 동작
NIO를 지탱하는 기술 정리
1. 운영체제에서 I/O작업을 할려면 os에 요청을 보내야함.
2. 이 운영체제는 그래서 h/w를 제어해서 가져옴
3. 문제는 운영체제가 막바로 h/w에 접근하는게 아니라 모드가 나눠짐(보안 때문에 나눔. 사용자가 직접 h/w 자원을 건드리지 못하게 할려고)
- 유저 모드 - 애플리케이션 레벨에서 요청을 받는 통로
- 커널 모드 - 유저 모드에서 넘어온 요청을 바탕으로 h/w를 제어
4. 이를 시스템 콜이라고 부름 즉, jvm → 시스템 콜 → 커널 → 디스크컨트롤러 → 커널 버퍼 복사 → jvm 버퍼 복사
5. 근데 자바는 직접적으로 커널모드에 콜을 보내는게 아님
6. JVM위에서 동작하기 때문에 이를 통해 콜을 보냄(그래서 타 언어에 비해서 I/O작업 성능이 현저히 느림)
7. 일단은 운영체제에서는 어떤식으로 시스템 콜을 효율화 시켰느냐면 아래와 같음
- 버퍼 사용 - 버스로 옮기기
- Scatter/Gather 사용 - n 개의 버퍼가 있으면 커널모드에서 n 번의 시스템 콜이 일어남 그러면 비효율 그래서 여기서 커널이 하나의 버퍼만 사용하도록 하는거 - 자바 Selector와 비슷한 맥락
- 가상메모리 사용 - 4.에 보면 복사라는 키워드가 있음 근데 결국 복사는 원본과 동일한 어떠한 복사본을 만들기에 느려짐 그래서 주소만 가지고 있도록하는 기술, 아래와 같음
- 메모리 맵 파일 - 위의 가상메모리를 구현하는 방법이다. 즉 가상 메모리라는건 논리적 개념이고 메모리 맵 파일은 물리적인 기술이다.
- 파일락 - 위의 메모리 맵 파일을 만들어서 들고가라고 하다가 충돌 날 수 있다. 그래서 락거는거 방법은 두가지 베타락(쓰기), 공유락(읽기)
실제로는 1이라는 주소만 들고 있고 커널에서 jvm 버퍼측으로 1을 전달 해서 “야 찾아가라.” 하는거임
가상메모리
idx | 1 | 2 | 3 | …. | 100 |
data | 어쩌고.txt | 배고프다.xls | 로또당첨기원.exe | ….. | 어휴.mp4 |
8.
그럼 자바에서 어떻게 I/O작업 성능을 향상 시켰느냐
- 버퍼 도입
- 네이티브 I/O 서비스를 제공하는 채널 도입(양방향 + 직접 시스템 메모리 버퍼에 데이터 쓰고, 읽기 가능)
- 셀렉터 도입 - 젤 초기는 Server Thread = Client 수 이렇게 1:1로 만듦 근데 이러면 서버터짐, 그래서 Server Thread 1개 = n 개의 Client 이런식으로 작업했다. 이게 폴링 방식 근데 셀렉터 도입이후 바뀜 그래서 예제가 잘못된 경우가 정말많음
버퍼를 쓸때 안쓸때는 거의 2배 차이 읽기 속도 더 날 수 있음
버퍼
본격 NIO
채널은 스트림의 확장, 발전 형태가 아님 - 게이트웨이라 볼 수 있다.
파일 채널은 추상형이다. 꺼내서 써라
파일 채널은 스레드에 안전하다.
기타 락킹도 알아둬라.
기존 지금 내 코드에서는 n:m 만큼의 Thread를 생성
그래서 고치면 폴링 방식이 된다.
그걸 더 발전 시키면 selector를 이용한 멀티플렉싱 ← 얘를 할려면 채널이랑 selector 조합이 필요
근데 만드는 것 자체는 간단하다. 구현체가 이미 존재해서
문제는 selector 이놈인데 reactor 패턴이라는 놈이 또 있다. 얼핏 보기에 내 생각에는 옵져버의 인프라 버전인 것 같다.
[핸들러, 이벤트] 한묶음으로 어디 담아 두고, 요청감지기로 기다리다가 요청이 들어오면 저 핸들러 묶음으로 요청을 던져버리고 실행까지 시키는 형태인것같다.
일단은 요까지만 하고 기존의 멀티 쓰레드 모델의 단점은
1.
많이 만들면 컨텍스트 스위치 부하가 심함(상대적으로)
2.
컴퓨터 리소스 부하가 심함(별로도 스택이 존재해서 1000만개 생긴다고 생각하면 엄청난 양의 부하가 생김, OOM 발생우려)
3.
빈번한 생성과 삭제로 인한 가비지(GC의 가장 큰 단점인 stw가 발생함 그럼 세상이 멈춤)
이 문제들 때문에 비블록킹 모델과 셀렉터가 등장
결과적으로 accept이게 블록되니깐 어쩔 수 없이 쓰레드를 클라이언트 마다 생성할 수 밖에 없었다.