본문 바로가기
Old/Network

Socket Programming

by onenewkong 2023. 7. 24.

블로킹

: 디바이스에 처리 요청을 걸어 놓고 응답을 대기하는 함수를 호출할 스레드에서 발생하는 대기 현상

  • 소켓뿐만 아니라 파일 핸들에 대한 함수를 호출했을 때도 이러한 대기 현상이 발생하는 것을 모두 블로킹이라고

 

송신 버퍼와 수신 버퍼

  • 송신 버퍼: 일련의 바이트 배열이라고 보면
  • 송신 버퍼의 크기는 고정 되어 있으나, 마음대로 크기를 변경할 있음

 

수신 버퍼가 가득 차면 발생하는 현상

  • 수신 함수가 수신 버퍼에서 데이터를 꺼내는 속도가 운영 체제가 수신 버퍼의 데이터를 채우는 속도보다 느리면
  • TCP 송신 함수로 송신 버퍼에 데이터를 쌓는 속도보다 수신 함수로 수신 버퍼에서 데이터를 꺼내는 속도가 느리다고 해서 TCP 연결은 끊어지지 않음 (실제 송신 속도가 느린 쪽에 맞추어 작동할 )
  • UDP 송신 함수로 송신 버퍼에 데이터를 쌓는 속도보다 수신 함수로 수신 버퍼에서 데이터를 꺼내는 속도가 느리면, 데이터그램 유실이 발생함

 

논블록 소켓

  • 네트워킹을 해야 하는 대상이 여럿이라면
  • 논블록 소켓을 사용하는 방법
  • 0바이트 송신
  • select() 혹은 poll()

 

논블록 소켓 장점)

  • 스레드 블로킹이 없으므로 중도 취소 같은 통제 가능
  • 스레드 개수 1개이거나 적어도 소켓을 여러 다룰 있음
  • 스레드 개수가 적거나 1개이므로 연산량이 낭비 되지 않음, 그리고 호출 스택 메모리도 낭비되지 않음

 

논블록 소켓 단점)

  • 소켓 I/O 함수가 리턴한 코드가 would block 경우 재시도 호출 낭비가 발생함
  • 소켓 I/O 함수를 호출할 입력하는 데이터 블록에 대한 복사 연산이 발생
  • connect() 함수는 재시도 호출을 하지 않지만, send() 함수나 receive() 함수는 재시도 호출해야 하는 API 일관되지 않는다는 문제가 있음
  • 소켓 함수 내부의 데이터 복사 부하

 

Overlapped I/O 다루는 방법

논블록 소켓이 다루는 데이터

  1. 소켓이 I/O 가능한 것이 있을 때까지 기다림
  2. 소켓에 대해 논블록 액세스를
  3. would block 발생했으면 그대로 두고, 그렇지 않으면 실행 결과 리턴 값을 처리

Overlapped I/O에서는..

  1. 소켓에 대해 Overlapped 액세를
  2. Overlapped 액세스가 성공했는지 확인한 성공했으면 결과값을 얻어와 나머지를 처리함

 

Overlapped I/O 다루는 방법

  1. Overlapped I/O '진행 중인 상태 현황' 보관하는 구조체를 먼저 준비
  2. 블로킹 소켓을 그대로 사용
  3. 소켓에 대한 Overlapped I/O 전용 함수 호출, 전용 함수는 항상 즉시 리턴
  4. 즉시 성공했다면 OK 리턴되고, 그렇지 않으면 완료를 기다리는 , I/O pending이라는 값이 즉시 반환됨
  5. Overlapped I/O 완료 여부는 확인하는 함수를 호출해보면 있음
  6. 완료라고 결과가 나오면 그냥 나머지 처리를
  7. 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 사용법)

  1. epoll 객체를 만듦
  2. 여러 소켓을 epoll 추가, 추가된 소켓의 I/O 가능 이벤트는 epoll 감지 가능
  3. 모든 소켓에 대한 select() 대신 epoll에서 이벤트를 꺼내 오는 함수를 호출, 함수는 사용자가 원하는 시간까지만 블로킹되며, 전에 이벤트가 생기는 순간 즉시 리턴함
  4. 이벤트에 대해 루프를 돌며 이벤트가 가리키는 소켓 객체와 사용자 정의 값을 꺼내
  5. 원하는 처리

 

에지 트리거 주의사항

  • 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 사용법)

  1. IOCP 객체를 만듦
  2. 여러 소켓과 소켓에 대응하는 원하는 정수 (epoll userptr 동일) IOCP 추가
  3. 추가된 소켓의 I/O 이벤트는 IOCP 이용하여 감지할 있음, I/O 하고 싶으면 Overlapped I/O
  4. 모든 Overlapped status 객체에 대한 GetOverlappedResult 대신 IOCP에서 완료 신호를 꺼내오는 함수를 호출, 함수는 사용자가 원하는 시간까지만 블로킹되며, 전에 이벤트가 생기면 즉시 리턴
  5. 이벤트가 가리키는 Overlapped statud 객체와 대응하는 userptr값을 꺼내 원하는 처리를
  6. 추가로 I/O 계속 하고 싶으면 Overlapped I/O 걸면

 

IOCP Accept처리

  1. IOCP listen socket L 추가했다면, L에서 TCP 연결을 받을 경우 이에 대한 완료 신호가 IOCP 추가됨
  2. 사전에 이미 AcceptEx Overlapped I/O 상태여야
  3. 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