일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- Specular
- Toon Shader
- URP
- AppSW
- Three(Two) Tone Shading
- 벡터
- Windows Build
- Rim Light
- URP로 변경
- Cell Look
- ASW(Application SpaceWarp)
- 메모리 누수
- 작업 집합
- Cartoon Rendering
- 프로그래밍 기초
- C언어
- 개인 바이트
- 3d
- Virtual Byte
- ColorGradingLutPass
- working set
- Cell Shader
- OculusMotionVectorPass
- 가상 바이트
- VR
- 게임 수학
- Private Bytes
- Today
- Total
WinCNT
Socket Programming in C/C++ 본문
TCP/IP 4계층과 소켓
인터넷의 핵심인 TCP/IP는 데이터 전송 과정에서의 역할에 따라
응용 계층, 전송 계층, 인터넷 계층, 네트워크 인터페이스 계층이라는 4개의 계층으로 구성된다
응용 계층과 전송 계층을 소통하기 위해 사용하는 것이 Socket이다
이 Socket을 프로그래밍하므로써 응용 계층에서 송수신 데이터를 다룰 수 있게 된다
소켓이란?
네트워크에서 소켓이란 컴퓨터 네트워크를 경유하는 프로세스 간 통신의 종착점이다
오늘날 대부분의 통신은 인터넷 프로토콜을 기반이므로, 대부분의 네트워크 소켓은 인터넷 소켓이다.
네트워크 통신을 위한 프로그램들은 소켓을 생성하고, 이 소켓을 통해서 서로 데이터를 교환한다
전송 계층, 인터넷 계층, 네트워크 인터페이스 계층의 데이터들은 응용 계층에서 다룰 수 없다
메모리에 올라와 있는 있어야 응용 계층에서 다룰 수 있다(즉, 코딩할 수 있게 된다)
이 때 필요한 것이 소켓(!!)이다
Windows OS에서는 OS가 소켓을 커널 오브젝트로 관리한다
(다시 말해 네트워크를 담당하는 커널 오브젝트을 소켓이라 함)
프로세스에서 소켓을 생성하면 윈도우 OS가 소켓 커널 오브젝트를 생성하고 그 핸들을 돌려준다
또한 OS가 소켓 커널 오브젝트를 만들 때 디폴트로 버퍼(소켓 버퍼)가 생성된다
(옵션으로 조정 가능)
소켓을 많이 만들게 되면 소켓마다 소켓 버퍼가 생성될 것이고
결국 커널 영역의 메모리가 넘처서 블루 스크린이 뜰 것이다
이 소켓(핸들)을 이용해서 커널에 전송 계층의 데이터에 대한 읽고 쓰기를 부탁하면
커널이 우선 소켓 커널 오브젝트의 버퍼에 데이터를 담고,
그 다음 OS가 소켓 버퍼를 이용해서 전송 계층의 데이터를 다룰 것이다
소켓을 다루는 방법
Windows OS의 경우 Winsock의 사용법을 알면 된다
하지만 그 다음에 만드는 것은 스스로의 머리를 짜내어서 만들어야 한다
소켓 프로그래밍이란
Listen은 TCP로 연결한다고만 알려준다
Bind는 서버에 필요한 것
Client에서는 포트 번호가 자동으로 할당되지만
서버에는 특정한 포트 번호를 직접 지정해야 한다
(그래야 클라이언트가 어디로 보내야 하는지 알 수 있으므로)
Listen(TCP 소켓) 상태에서 대기 중에 어떤 클라이언트가 Connet를 하면
Accept를 하면서 새로운 소켓(클라이언트 소켓)을 만든다
(반대로 Accept를 하지 새로운 소켓을 만들지 않는다)
이 때부터 서버와 클라이언트가 데이터를 주고 받을 준비가 됐다는 뜻이다
데이터의 주고 받음은 소켓 버퍼의 Read/Write로 이루어진다
Blocking(위의 그림) 방식이면 Read/Write할 데이터가 없으면 계속 기다린다
이를 피하기 위하는 방법으로는 비동기를 적용하는 방식이 있다
WSAAsyncSelect
비동기 방식으로 소켓의 상태를 통지받기 위해 사용하는 API 함수
WSAAsyncSelect(Listen, hWnd, WM_SOCKET, FD_ACCEPT | FD_CLOSE);
위의 코드는 Listen이라는 소켓이 FD_ACCEPT나 FD_CLOSE의 상태가 되면
윈도우 메시지로 통지(비동기)해달라고 설정하는 함수
case FD_ACCEPT:
clientSocket = accept(wParam, (SOCKADDR*)&clientAddr, &sockaddrLen);
WSAAsyncSelect(clientSocket, hWnd, WM_SOCKET, FD_READ | FD_WRITE | FD_CLOSE);
FD_READ가 발생하면 Recieve로 소켓의 수신 버퍼의 데이터를 가져오고,
다시 읽을 데이터가 있으면 통지해달라는 요청을 하게 된다
case FD_READ:
nRecv = recv((SOCKET)wParam, recvBuffer, DATA_BUFSIZE, 0);
만약 Receive를 했는데 수신 버퍼에 데이터가 남아있으면 OS가 다시 FD_READ를 발생시킨다
FD_READ와 Recieve의 코딩 실수의 예
1. FD_READ가 발생했는데 Receive를 하지 않을 경우
클라이언트 소켓에 대해서 요청을 하지 않으므로 FD_READ가 다시 발생하지 않음
이를 방지하기 위해서 0바이트라도 읽어와야 한다
2. 수신 버퍼를 비우지 않는 경우
수신의 버퍼가 꽉 차게 되면 클라이언트 쪽에 버퍼가 꽉 찼다고 알려준다
그러면 클라이언트는 송신 버퍼에 데이터를 계속 채우고 송신은 하지 않게 되고
결국 송신 버퍼도 꽉 차게 되면 would block이 발생한다
TCP 소켓 연결 후에...
TCP는 소켓이 2개 필요하다
Listen용 소켓
open, bind, listen의 3단계
open은 소켓을 만드는 것
bind는 지정된 주소와 포트 번호에 바인딩하는 것
listen은 서버 소켓을 수동 모드로 설정하여 클라이언트가 연결을 설정하기 위해 서버에 접근할 때까지 기다리는 것
디폴트가 오픈, 바인드, 웨이트이지만 문제는 블로킹이 디폴트이다
이벤트 발생
비동기로 바꾸고 싶으면?
데이터가 도착한 건 모르지만
비동기는 OS으로부터 통지(notify)를 받는 모델
비동기를 만드는 방법은 2가지
1. 윈도우 메시지
2. Async
어떤 소켓에 사건이 발생하면 커널의 이벤트 객체로 앱에게 통지해주세요
그럼 WinProc에서 처리하겠습니다 라는 모델
AsyncSelect든 EventSelect든 비동기 소켓이다
FD_RECV은 수신 버퍼에 읽을 것이 있다고 OS가 통지하는 것
(실제 도착 시간은 더 전일 수 있다)
수신 버퍼를 다 안 읽었다면 OS가 다시 통지해준다
비동기 소켓은 읽을 것이 없어도 would block(10035)으로 다시 돌아온다
Client가 Send()로 Server에 보내는 상황(TCP)에서
서버의 수신 버퍼에 데이터가 꽉 찼으면
클라이언트의 데이터도 송신 버퍼에 계속 쌓이게 되고
송신 버퍼도 다 차면 would block이 발생하고 FD_WRITE이 뜨게 된다
따라서 FD_WRITE는 정상적인 상황에서는 잘 발생하지 않는다
Remote 관리는 어떻게 할 것인가
Winsock 버퍼에 있는 것을 읽어 오는 것
Listen 소켓 하나랑 클라이언트 소켓 여러 개
송신 버퍼도 별도로 필요하다
FirstWinServer
솔루션
주기적으로 Update 등으로 OnRecv 등을 하는 것이 좋다
업데이트 할 때 타임 아웃도 관리하면서 병목 현상을 제어하는 것이 좋음
참고 사이트)
https://www.geeksforgeeks.org/socket-programming-cc/
SSS
'게임 프로그래밍(학습 내용 정리) > 네트워크 프로그래밍' 카테고리의 다른 글
TCP/IP 계층 구조 (0) | 2022.05.02 |
---|---|
네트워크로 데이터를 송신하는 과정 (0) | 2022.04.26 |
UDP vs TCP and Socket (0) | 2022.04.25 |
컴퓨터 네트워크의 구성 요소 3가지 (0) | 2022.04.11 |
소켓 (0) | 2022.04.05 |