네트워크 프로그래밍 단계
Client
소켓 생성(Socket) -> 서버 소켓 연결(Connect) -> Data 송/수신(Send/Recv) -> 소켓 끊기(Close)
Server
소켓 생성 -> 소켓 묶기 -> 소켓 접속 대기 -> 연결 소켓 생성 -> Data 송/수신 -> 소켓 끊기
Socket -> Bind -> Listen -> Accept -> Recv/Send -> Close

Socket 생성 (SOCKET)
파라미터에 맞는 소켓을 생성해주는 함수이다.
SOCKET WSASocket(int af, int type, int protocol, LPWSAPROTOCOL_INFO IpProtocolInfo, GROUP g, DWORD dwFlags)
이 함수의 인수
af: address family. 보통 AF_INET <- IPv4를 사용할 때 사용하는 상수 IPv6는 AF_INET6을 사용한다.
type: 소켓의 타입. 보통은 tcp의 SOCKET_STREAM udp의 SOCK_DGRAM
protocol: 사용할 프로토콜 종류. 보통은 IPPROTO_TCP or IPPROTO_UDP
IpProtocolInfo: 프로토콜의 정보. 보통은 NULL값으로 둔다.
dwFlags: 소켓의 속성. 보통은 사용하지 않기에 0으로 두는데, OVERLAPPED_IO나 IOCP를사용할때에는 사용하게 된다. 그때에는 WSA_PROTOCOL_OVERLAPPED를 사용한다.
소켓의 연결 (Connect)
대기하고 있는 상대방의 소켓에 자신의 소켓을 연결하는 함수
int WSAConnect(SOCKET s, const struct sockaddr* name, int namelen, LPWSABUF IpCallerData, LPWSABUF IpCalleeData, LPQOS IpSQOS, LPQOS IpGQOS)
이 함수의 인수
s: WSASocket에서 만든 소켓을 넣어준다.
Name: 소켓의 주소를 담는 포인터
Namelen: 소켓 주소의 길이
IpCallerData, IpCalleeData: 접속도중 상대방에서 송/수신 받을 유저 데이터의 포인터, 수업때 다루진 않음.
LPQOS : 안알려주셔서 찾아봤는데 QOS는 Quality Of Service의 약자로, 어플리케이션의 동작에 따라 네트워크
디바이스가 트래픽을 조작하는 것 이라는데 이것도 안쓰임. 넘어가
Socket에서 데이터 받기 (RECV)
WSARecv를 통해 받는다. 여기서 왜 Recv가 아니냐?
-> 여러가지 고성능 API를 사용하기 위해서 Recv에서 확장된 WSARecv를 사용한다.
int WSARecv(SOCKET s, LPWSABUF IpBuffers, DWORD dwBufferCount, LPDWORD IpNumberofBytesRecvd, LPDWORD IpFlags, LPWSAOVERLAPPED IpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE IpComletionRoutine)
이 함수의 인수
s: 소켓
IpBuffers: Recv한 데이터를 저장하는 버퍼.
dwBufferCount: 버퍼의 개수
여기서 버퍼가 담을 수 있는 데이터의 크기는 구조체 안에 있음
IpNumberofBytesRecvd: 내가 몇Byte를 Recv했는지 모르기 때문에 여기서 값을 전달받음
IpFlags: MSG_PEEK(데이터 존재 유무 확인), MSG_OOB(우선도착) 등등의 옵션?을 넣어줌. 강의에서는 잘 사용 X
IpOverlapped와 IpComletionRoutine는 뒤 게시물에서 정리하여 올리도록 하겠습니당
여기서 WSABUF란?
흩어져있는 값들을 관리하는 구조 버퍼를 여러개를 둘 수 있게 하기 위해서 사용한다 하심
예를들어 패킷 세개를 보낼 때 패킷 세개를 하나의 버퍼에 copy해서 한꺼번에 보내게 된다면 메모리 복사를 해야하기 때문에 OverHead가 굉장히 큼.
따라서 패킷 세개에 대한 주소값과 크기만을 담은 값을 보내게 된다면 성능향상에 도움이 된다.
이 기술은scatter gather I/O라고 하는데, boost/asio에서도 적용된다고 한다.
정확한건 마소 독스 >> https://docs.microsoft.com/ko-kr/windows/win32/winsock/scatter-gather-i-o-2

소켓 묶기 (BIND)
포트를 선점하여 다른 프로그램이 사용하지 못하도록 하는 함수
int bind(SOCKET s, const struct sockaddr* name, int namelen)
name과 namelen은 상대 소켓의 주소와, 길이를 나타내는데, 왠만해서는 모든 주소로부터 접속을 허용하잔슴? 그때는
INADDR_ANY모든 주소로부터 접속을 허용시킴. 다른 국가, IP만 막고싶은건 라우터를 통해 하는거. 우리는 할일이 많다!
소켓 접속 대기 (LISTEN)
소켓이 접속을 받을 수 있도록 만드는 함수
int listen(SOCKET s, int backlog)
Backlog: accept전 접속 대기 큐의 최대 연결가능숫자. 대용량게임서버에선 SOMAXCONN값을 주로 넣음
연결 소켓 생성 (ACCEPT)
연결된 소켓을 만드는 함수
SOCKET WSAAccept(SOCKET s, struct sockaddr* name, LPINT addrlen, LPCONDITIONPROC IpfnCondition, DWORD dwCallbackData)
이 함수의 인자
s: Accept할때만 사용하는, 현재 listen을 하고있는 소켓.
addrlen: 클라이언트에 연결하면 어떤 클라이언트에 연결했나 클라이언트의 주소를 넣어줌.
중간에 접속이 끊어졌다 재접속했는지 확인해야하고, IP를 밴했다면 그것도 확인해야 함.
IpfnCondition, dwCallbackData: WSA로 확장하며 생김. Accept를 하기 전, 주소가 내가 받아도 되는지 판단을 하는
파라미터. 이전에 특정 IP나 특정 나라를 차단할 때 쓰라고 만들었지만, 서버가 이걸 하고있을 여유가 없다
그래서 라우터단에서 해줌
WSAAccept에서 리턴한 SOCKET : 이 클라이언트와 1대1로 연결되는 소켓. send/recv할때는 이 소켓을 사용해야 함.

위 게시물은 현 한국공학대학교 게임공학과 교수님이신 정내훈 교수님의 강의를 듣고 정리한 내용입니다.
'공부' 카테고리의 다른 글
| 게임서버 프로그래밍 #1 (네트워크의 기초) (0) | 2022.07.05 |
|---|---|
| 간단한 C 포인터 문제 (0) | 2022.06.11 |