블로킹
: 디바이스에 처리 요청을 걸어 놓고 응답을 대기하는 함수를 호출할 때 스레드에서 발생하는 대기 현상
- 소켓뿐만 아니라 파일 핸들에 대한 함수를 호출했을 때도 이러한 대기 현상이 발생하는 것을 모두 블로킹이라고 함
송신 버퍼와 수신 버퍼
- 송신 버퍼: 일련의 바이트 배열이라고 보면 됨
- 송신 버퍼의 크기는 고정 되어 있으나, 마음대로 크기를 변경할 수 있음
수신 버퍼가 가득 차면 발생하는 현상
- 수신 함수가 수신 버퍼에서 데이터를 꺼내는 속도가 운영 체제가 수신 버퍼의 데이터를 채우는 속도보다 느리면
- TCP 송신 함수로 송신 버퍼에 데이터를 쌓는 속도보다 수신 함수로 수신 버퍼에서 데이터를 꺼내는 속도가 느리다고 해서 TCP 연결은 끊어지지 않음 (실제 송신 속도가 느린 쪽에 맞추어 작동할 뿐)
- UDP 송신 함수로 송신 버퍼에 데이터를 쌓는 속도보다 수신 함수로 수신 버퍼에서 데이터를 꺼내는 속도가 느리면, 데이터그램 유실이 발생함
논블록 소켓
- 네트워킹을 해야 하는 대상이 여럿이라면
- 논블록 소켓을 사용하는 방법
- 0바이트 송신
- select() 혹은 poll()
논블록 소켓 장점)
- 스레드 블로킹이 없으므로 중도 취소 같은 통제 가능
- 스레드 개수 1개이거나 적어도 소켓을 여러 개 다룰 수 있음
- 스레드 개수가 적거나 1개이므로 연산량이 낭비 되지 않음, 그리고 호출 스택 메모리도 낭비되지 않음
논블록 소켓 단점)
- 소켓 I/O 함수가 리턴한 코드가 would block인 경우 재시도 호출 낭비가 발생함
- 소켓 I/O 함수를 호출할 때 입력하는 데이터 블록에 대한 복사 연산이 발생
- connect() 함수는 재시도 호출을 하지 않지만, send() 함수나 receive() 함수는 재시도 호출해야 하는 API가 일관되지 않는다는 문제가 있음
- 소켓 함수 내부의 데이터 복사 부하
Overlapped I/O 다루는 방법
논블록 소켓이 다루는 데이터
- 소켓이 I/O 가능한 것이 있을 때까지 기다림
- 소켓에 대해 논블록 액세스를 함
- would block이 발생했으면 그대로 두고, 그렇지 않으면 실행 결과 리턴 값을 처리
Overlapped I/O에서는..
- 소켓에 대해 Overlapped 액세를 검
- Overlapped 액세스가 성공했는지 확인한 후 성공했으면 결과값을 얻어와 나머지를 처리함
Overlapped I/O 다루는 방법
- Overlapped I/O를 걸 때 '진행 중인 상태 현황'을 보관하는 구조체를 먼저 준비
- 블로킹 소켓을 그대로 사용
- 소켓에 대한 Overlapped I/O 전용 함수 호출, 전용 함수는 항상 즉시 리턴
- 즉시 성공했다면 OK가 리턴되고, 그렇지 않으면 완료를 기다리는 중, 즉 I/O pending이라는 값이 즉시 반환됨
- Overlapped I/O 완료 여부는 확인하는 함수를 호출해보면 알 수 있음
- 완료라고 결과가 나오면 그냥 나머지 처리를 함
- Overlapped I/O를 수신했다면 data 객체에 수신된 데이터가 자동으로 채워져 있을 것, 이를 그냥 액세스 함
Overlapped I/O 백그라운드에서 액세스로 인한 주의사항
- Overlapped I/O 함수는 즉시 리턴되지만, 운영체제로 해당 I/O 실행이 별도로 동시간대에 진행되는 상태임
- 운영체제는 소켓 함수에 인자로 들어갔던 데이터 블록을 백그라운드에서 액세스함
- 호출한 Overlapped I/O 전용 함수가 비동기로 하는 일이 완료(complete)될 때까지는 소켓 API에 인자로 넘긴 데이터 블록을 제거하거나 내용을 변경해서는 안됨
- Overlapped status 구조체 또한 운영체제에서 백그라운드로 액세스 중이므로 중간에 없애거나 내용을 변경해서도 안됨
Overlapped I/O 장단점)
장점)
- 소켓 I/O 함수 호출 후 would block 값인 경우 재시도 호출 낭비가 없음
- 소켓 I/O 함수를 호출할 때 입력하는 데이터 블록에 대한 복사 연산을 없앨 수 있음
- send, receive, connect, accept함수를 한 번 호출하면 이에 대한 완료 신호는 딱 한 번만 오기 때문에 프로그래밍 결과물이 깔끔함
- I/O completion port와 조합하면 최고 성능의 서버를 개발할 수 있음
단점)
- 완료되기 전까지 Overlapped status 객체가 데이터 블록을 중간에 훼손하지 말아야 함
- 윈도우 플랫폼에서만 제공하는 기능
- accept, connect 함수 계열의 초기화 복잡함
Overlapped I/O에서 I/O 실행 상태
- Overlapped 송신이 진행 중이고 완료가 아직 안되어있으면 'Overlapped 송신이 아직 완료 대기 중(pending)'이라고 함
- Overlapped 수신이 진행 중이고 완료가 아직 안되어있으면 'Overlapped 수신이 완료 대기 중'이라고 함
- 이를 통칭 'I/O 완료 대기 중' 혹은 'I/O 실행 중'이라고 함
리액터 패턴과 프로액터 패턴
: 논블록 소켓을 뒤늦게.. 라는 의미의 리액터 패턴이라고 함, Overlapped I/O는 미리.. 라는 의미의 프로액터 패턴이라고 함
epoll
: 소켓이 I/O 가능 상태가 되면 이를 감지하여 사용자에게 알림을 해주는 역할을 함, 이때 어떤 소켓이 I/O 가능 상태인지 알려줌
epoll 사용법)
- epoll 객체를 만듦
- 여러 소켓을 epoll에 추가, 추가된 소켓의 I/O 가능 이벤트는 epoll로 감지 가능
- 모든 소켓에 대한 select() 대신 epoll에서 이벤트를 꺼내 오는 함수를 호출, 이 함수는 사용자가 원하는 시간까지만 블로킹되며, 그 전에 이벤트가 생기는 순간 즉시 리턴함
- 각 이벤트에 대해 루프를 돌며 이벤트가 가리키는 소켓 객체와 사용자 정의 값을 꺼내 옴
- 원하는 처리
에지 트리거 쓸 때 주의사항
- I/O 호출을 한 번만 하지 말고 would block이 발생할 때까지 반복해야 함
- 소켓은 논블록으로 미리 설정되어 있어야 함
connect()와 accept()의 I/O 가능 이벤트
- epoll은 connect()와 accept()에서도 I/O 가능 이벤트를 받을 수 있음
- connect()는 send 이벤트와 동일하게, 그리고 accept()는 receive 이벤트와 똑같이 취급됨
- 리스닝 소켓에 대한 receive 이벤트를 받을 경우, accept()를 호출하면 새 TCP 연결의 소켓을 얻을 수 있음
Overlapped 자료구조
- Overlapped I/O를 위해서는 WSAOVERLAPPED라는 자료구조를 만들어서 모든 Send/Recv에 초기화해서 넣어주어야 함
- send/recv는 사용할 수 없고 WSASend/WSARecv를 사용해야 함, 버퍼는 WSABUF 사용
다중 접속처리: 여러 개의 소켓이 필요하고 소켓마다 그 소켓에서 사용하는 버퍼 자료 구조 필요
Callback 함수에서 소켓: 소켓 정보가 따로 오지 않음, WSAOVERLAPPED에 끼워 넣어야 함
IOCP
: 소켓의 Overlapped I/O가 완료되면 이를 감지해서 사용자에게 알려주는 역할
- 사용자는 IOCP에서 I/O가 완료되었음을 알려주는 완료 신호를 꺼낼 수(pop) 있음
- 소켓 개수가 1만개라고 해도 이 중에서 I/O가 완료된 것들만 IOCP를 이용해 바로 얻을 수 있으므로, 모든 소켓에서 루프를 돌지 않아도 됨
IOCP 사용법)
- IOCP 객체를 만듦
- 여러 소켓과 소켓에 대응하는 원하는 정수 값(epoll의 userptr과 동일)을 IOCP에 추가
- 추가된 소켓의 I/O 이벤트는 IOCP를 이용하여 감지할 수 있음, I/O를 하고 싶으면 Overlapped I/O를 검
- 모든 Overlapped status 객체에 대한 GetOverlappedResult 대신 IOCP에서 완료 신호를 꺼내오는 함수를 호출, 이 함수는 사용자가 원하는 시간까지만 블로킹되며, 그 전에 이벤트가 생기면 즉시 리턴
- 이벤트가 가리키는 Overlapped statud 객체와 대응하는 userptr값을 꺼내 온 후 원하는 처리를 함
- 추가로 I/O를 계속 하고 싶으면 Overlapped I/O를 또 걸면 됨
IOCP Accept처리
- IOCP에 listen socket L을 추가했다면, L에서 TCP 연결을 받을 경우 이에 대한 완료 신호가 IOCP에 추가됨
- 단 사전에 이미 AcceptEx로 Overlapped I/O를 건 상태여야 함
- IOCP로 L에 대한 이벤트를 얻어 왔지만, 앞서 Overlapped aceept처럼 SO_UPDATE_ACCEPT_CONTEXT와 관련된 처리를 해주어야 새 TCP 소켓 핸들을 얻어올 수 있음
IOCP 성능상 유리한 기능
: IOCP는 스레드 풀을 쉽게 구현할 수 있게 하는 반면, epoll은 그렇지 않음
epoll에서 스레드 풀링 구현하기
: 스레드 개수만큼 epoll 객체를 둠
- 각 스레드는 자기만의 epoll을 처리
- 여러 소켓은 이들 epoll 중 하나에만 배정
IOCP 성능상 유리한 기능
- IOCP를 쓰는 윈도우 서버에서는 연결 받기와 수신을 소켓 함수 호출 한 번으로 끝낼 수 있음
- 부가적으로 연결된 소켓의 끝점 정보를 얻는 것도 같이 끝내버릴 수 있어 프로그램 최적화에 유리함
소켓 프로그래밍에서 고려해야 할 점
- IP주소 값이 아니라 도메인 이름으로 접속하려면 도메인 이름에서 IP 주소를 변환하는 일을 해야 함 -> getaddrinfo()
- iOS 등 FreeBSD 계열 운영체제에서 소켓 프로그래밍을 할 때는 epoll과 비슷한 것을 사용할 수 있는데, 그 이름은 kqueue임
- 소켓 함수를 직접 이용하는 것이 불편하다면 boost 라이브러리의 asio를 사용하는 것도 좋은 방법
- C/C++에서 소켓 함수는 매우 까다로움, 하지만 C#, Java같은 고수준 언어에서는 소켓 클래스가 매우 정갈하게 정리되어 있어 사용하기가 훨씬 편리함
'Old > Network' 카테고리의 다른 글
게임 네트워킹 (0) | 2023.07.27 |
---|---|
게임 서버와 클라이언트 (0) | 2023.07.24 |
컴퓨터 네트워크 (0) | 2023.07.24 |
Multi Threading (0) | 2023.07.24 |
REST / REST API (0) | 2023.02.11 |