소켓 프로그래밍
1. 블로킹 소켓
블로킹
디바이스에 처리 요청을 걸어 놓고 응답을 대기하는 함수를 호출할 때
스레드에서 발생하는 대기 현상
블로킹이 발생하는 스레드에서는 CPU 연산을 하지 않는다
CPU 사용량이 0% , 스레드는 Waitable 상태
기록하려는 데이터가 디스크에 완전히 기록될 때까지 Waitable 상태를
유지한다
2. 블로킹과 소켓 버퍼
송신버퍼
- 일련의 바이트 배열
- 크기는 고정되어 있으나, 마음대로 크기를 변경할 수 있음
- FIFO 형태로 작동
- 송신버퍼가 가득 차 있을 때 푸시하면 블로킹 발생
- 송신버퍼는 디폴트로 수천 바이트를 담을수 있다
3. 네트워크 연결받기 및 수신
- 수신할 수 있는 데이터가 없으면 블로킹이 일어난다
4. 수신 버퍼가 가득 차면 발생하는 현상
수신 버퍼에서 데이터를 꺼내는 속도가 수신 버퍼의 데이터를 채우는 속도보다
느릴 경우
- TCP인 경우 연결이 끊어지지는 않는다. 단지 실제 송신속도가 느린 쪽에 맞추어 작동할 뿐이다
- UDP인 경우 데이터그램이 그냥 버려진다. 송신함수에 블로킹이 발생하지 않는다
라우터에 연결된 한곳 A에서 도착하는 패킷이 압도적으로 많으면 A이외의
다른 곳들은 네트워크 경쟁에서 밀리게 된다
TCP는 송신자측 운영체제가 알아서 초당 송신량을 줄여 다른 네트워킹이 경쟁에서 밀리지 않는다
UDP는 속도 제한 없이 마구 송신하면 주변 네트워킹이 경쟁에서 밀린다
주변 네트워킹이 두절되기도 하는데 이른 혼잡 현상이라 한다.
5. 논블록 소켓
네트워킹 해야하는 대상이 여럿일 때
네트워킹 대상 개수만큼 스레드를 만든다
네트워킹 대상이 많으면 스레드 간에 컨텍스트 스위치가 대량 발생
자원낭비로 이어짐
운영체제의 API 사용
논블록 소켓 API 사용법
- 소켓을 논블록 소켓으로 전환
- 송신,수신,연결과 관련된 함수 호출
- 무조건 이 함수 호출에 대해 즉시 리턴
- 리턴 값은 성공 혹은 Would block
Would block
블로킹이 걸릴 상황이었다는걸 말해준다
논블록 소켓을 사용하면 한 스레드에서 여러 소켓을 한꺼번에 다룰 수 있다
논블록 소켓을 사용하면 블로킹이 난무하는 문제가 사라진다
- 많은 수의 소켓 데이터를 지연 시간 없이 처리할 수 있다
Connect() 함수가 would block이 리턴된 경우
- 0바이트 송신을 이용해 would block이 끝났는지를 확인
0바이트 송신
TCP는 스트림 기반 프로토콜이기 때문에 0바이트를 보내는 것은 사실상 아무것도 하지 않는 셈
select / poll
송신 버퍼에 빈 공간이 생기거나 수신 버퍼에 뭔가가 들어온다면 그 상황을 알려주는 함수이다
소켓에 I/O 처리가 가능한 소켓이 하나라도 있을 경우 즉시 리턴하고 그렇지 않은 경우 타임아웃 시간만큼 기다린다
I/O 가능
해당 소켓에 대해 소켓 함수를 호출하면 would block이 아닌 다른결과가 나온다는 의미
6. Overlapped I/O 혹은 비동기 I/O
논블록 소켓의 장점
- 중도 취소 같은 통제가 가능
- 소켓을 여러 개 다룰 수 있음
- 연산량이 낭비되지 않음
- 호출 스택 메모리도 낭비되지 않음
논블록 소켓의 단점
리턴한 코드가 would block인 경우 헛발질을 한다
TCP의 send, receive UDP의 receive는 문제가 없다
UDP인 경우 Send() 처리에서 문제가 있다
- TCP처럼 데이터의 일부만 보낼 수 없으므로 송신 버퍼에 데이터 전체가 들어갈 공간이 없으면 Would block이 된다
- I/O 가능(송신버퍼에 1byte라도 자리가 있음)이지만 데이터 그램의 크기가 1byte를 넘긴다면 쓸데없이 연산량을 늘리는 셈(I/O가능이니 재시도를 계속하게 됨)
입력하는 데이터 블록에 대한 복사 연산이 발생
- CPU 안의 캐시에 없는 데이터를 엑세스할 때 RAM을 엑세스하는데 이 속도는 굉장히 느리다
sned()함수나 receive()함수는 재시도 호출해야하는 API가 일관되지 않는다는 문제
Overlapped, 비동기 I/0
논블록 소켓의 단점을 모두 해결해 준다
I/O처리를 스레드가 하는 것이아니라 Device Driver에 권한을 넘김으로써 cpu가 놀지 않고 다른일을 할 수 있게 해준다
중첩의 의미
우리의 코드가 무언가를 하고 있을 때 이와 별개로 운영체제가 마음대로 작업하던 데이터를 건드림
Overlapped I/O 전용 함수가 비동기로 하는일이 완료될 때 까지는 소켓 API에 인자로 넘긴 데이터 블록을 제거하거나 내용을 변경해서는 안된다
Overlapped I/O 전용 송수신 함수를 호출하면 운영체제는 송신할 데이터가 저장되어 있는 메모리 블록 자체를 송신 버퍼로 사용해 버린다
수신할 떄도 마찬가지이며 복사가 생기지 않는다
윈도우에서만 제공해준다
Overlapped 비동기 I/O와 Non-Blocked Socket의 차이점
I/O 처리를 비동기로 하여 복사하는 작업 동안에 Block이 되지 않는다
I/O 처리를 순서대로 하지 않는다.(디스크에 가까운 순서대로 처리)
ZERO-COPY를 통해 소켓 버퍼로의 복사를 건너 뛰고 바로 유저 버퍼에 데이터를 복사한다
따라서 작업하는 동안에 유저 블록을 터치해서는 안되는 것.
너무 많은 양의 I/O가 생길 경우 에러를 발생시킨다.
리액터 패턴
- 상태 확인 후 무언가를 한다
- 논블록 소켓
- I/O를 시도한다(성공할 수도 실패할 수도 있다)
- 실패할 때는 I/O 가능을 기다린 후 I/O를 재시도한다
- 성공할 때는 상황을 종료한다
프로액터 패턴
- 무조건 저지른 후 결과를 확인한다
Overlapped I/O (비동기)
- I/O를 시행(무조건 성공)한다
- I/O 완료를 기다린다
- 상황을 종료한다
프로액터는 이벤트에 명령을 내리는것. 리액터는 이벤트에 수행 가능하다는 것을 알리는 것
7. epoll
- 소켓이 I/O 가능 상태가 되면 이를 감지해서 사용자에게 알림을 해주는 역할을 한다
- 소켓이 1만 개라고 하더라도 이 중에서 I/O 가능이된 것들만 epoll을 이용해서 바로 얻을 수 있다
- 리눅스와 안드로이드에서만 사용 가능
- 스레드 풀 구현이 어렵다
8. IOCP
- 소켓의 Overlapped I/O가 완료되면 이를 감지해서 사용자에게 알려 주는 역할을 한다
- 소켓 개수가 1만 개라고 하더라도 이 중에서 I/O가 완료된 것들만 IOCP를 이용해서 바로 얻을 수 있기 때문에 모든 소켓에서 루프를 돌지 않아도 된다
- 윈도우에서만 사용 가능하다
- 스레드 풀을 쉽게 구현할 수 있다
'게임 서버 프로그래밍 > 게임 서버 프로그래밍 교과서' 카테고리의 다른 글
#6. 프라우드넷 (0) | 2020.02.17 |
---|---|
#5. 게임 네트워크 (0) | 2020.02.17 |
#4. 게임 서버와 클라이언트 (0) | 2020.02.17 |
#2. 컴퓨터 네트워크 (0) | 2020.02.17 |
#1 프로그램과 프로세스 (2) | 2020.02.17 |