iocp기반임. 250401/250403 수업 (아직 미완성..)
비동기 다중접속에서 Accept는 AcceptEx로 해준다..
일단 여기서도 EXP_OVER로 OVERLAPPED 구조체를 확장시켜줘서 사용함.
각 EXP_OVER는 자기가 어떤... 작업인지 정보를 갖고있음
(수업에선 enum통해서 작업 구분함.. IO_RECV, IO_SEND, IO_SEND로..)
EXP_OVER안에... os에 넘길 비동기 정보 WASOVERLAPPED구조체가 있음
Overlapped 구조체... 모든 send, recv는 이 구조체가 필요.
하나의 구조체를 여러 호출에서 사용하는건 불가능!! 개당 하나씩 필요.
소켓당, recv호출은, 무조건 하나씩...!!!!
소켓당, send호출은 여러개 가능하다.. -> 이게 브로드 캐스팅
└ (개수제한이 없어 new,delete사용, 성능을 위한 공유 pool사용)
미완성 EXP_OVER이긴 하나...
_accept_socket은 do_accept 함수에서 WSASocket에서 만든 소켓을 이 안에 저장.
이 새로만든 소켓으로 AcceptEx를 호출해서 클ㄹ ㅏ접속을 기다렸다가..
접속이 완료되면?!!? -> IO_ACCEPT가 올거임->그러면 ㄹㅇ로 객체(클라)를 생성해준다
그 소켓을 SESSION에 넘겨서 그 클라 전용 소켓으로 사용하겠다는 것
그 소켓으로 g_users에 추가해줘서 객체 생성.
do_accept로 또다른 클라 접속 수락 준비!
(참고로 실제 접속을 하는건 os가 한다.. AcceptEx()는 그냥 수락 과정을 os한테 맡겨놓는 비동기 예약 함수임.
객체는 생성되자마자.. 받을준비를 함.
SESSION에는 여러 정보가 들어있다.. id, 네트워크 접속 정보, 게임 정보..(name, x,y등)
우리는 데이터를 보낼 때 패킷으로 보냄.
그 패킷을 구성하는 데이터는 지금.. SESSION안에 들어있는 정보에서 꺼내서... EXP_OVER안 _buffer에 복사해서 전송하는 것임..
패킷 안에 데이터를 전부 복사시켰으면 SEND를 통해서 보낸다..
모든 패킷은... 기본구조로 [총 길이][패킷 타입][데이터].. 를 가짐.
제일 처음에 패킷 사이즈.(패킷 길이) Length,
그다음 패킷 타입,
그다음 데이터(실제 전송할 내용)
모든 클라와 서버는 같은 패킷 프로토콜을 사용해야함.. 둘이 다르면 안된다..
SESSION에서 객체 생성되자마자 받을준비-> do_recv를 실행.
do_recv에서는.. 메모리 초기화를 해주고, WSARecv를 해준다.(받기를 예약걸어두고 튐.)
그리고나서 main문에서 나중에 GetQueuedCompletionStatus()를 통해 완료되면 큐에서 꺼내져서..
IO_RECV를 받았을테니, 패킷 단위로 데이터를 해석하기 시작!
여기서 왱 unsigned_char를 쓰느냐?.. 굳이 char를 써도 돌아갔는데 왜 unsigned를 붙이냐..에 대해
unsigned char는 부호가 없음.(0~255) char는 (-128~127) -> 부호가 존재함(음수때문에.. 데이터 해석에 오류)
unsigned char는 항상 안전하대요.. 네트워크에서.. 주고받는 패킷은.. 숫자 그 자체가 아니라, 비트 정보
네트워크는 항상 비트 단위, 바이트 단위의 정수 데이터로 다뤄진다....
아무튼... 값이 잘못 해석될 수 있다! 정도만 알아두는걸로..
내 언어로 요약하면.. 네트워크 데이터는 부호가 없는 바이트 단위로 처리되므로, 데이터 해석 오류 방지를 위해 unsigned char를 사용한다!! 라고 기억하면 됨댕딩동
다시 IO_RECV로 돌아와서...
클라로부터 받은 데이터를.. 너 누구야?확인하기 위해
key를 통해 그 클라의 id를 확인.. 그 id에 해당하는 g_users를 꺼내온다.
그리고 그 아이를 user라는 객체로 생성해서 봐준다.
unsigned char*p = eo->_buffer;
eo는 EXP_OVER*.. 이번 수신 작업이 담긴 오버랩드 구조체임.
eo->_buffer는 그 받은데이터가 저장된 버퍼임!
아니 근데 어차피.. 클라는 패킷 하나씩 보내지 않나..?
근데 왜?? p=p+packet_size; 를 왜 해주는가에 대한 궁금증이 생김... 왜 굳이 패킷사이즈 단위로 while문 돌려서 모든 패킷을 확인하려는거지? 어차피 하난데????이런..
일단 패킷은 한번에 주고받는 데이터 단위.
WSARecv, WSASend가 다루는.. 1개의 완성된 데이터 블록..
네트워크는... 우리가 보낸대로 도착하지 않음. 클라가 WSASend로 각각 보내줘도..
서버에서는 연결된 패킷 3개가 붙어 올 수 있음.
그래서 이걸 하나씩 잘라서.. processpacket(p)에 넣어주는 거임..
한번의 수신으로 여러개의 패킷이 왔을때를 대비한 것..
꼭 여러개 안오더라도 하나씩만 온다면 루프는 어차피 1번만 돌고 끝나는 것이다....
그러나 현실은.. 패킷이 두개씩 올 수도 있고? 패킷이 잘려서 올수도 있고?(그래서 여기선 remained 사용)
packet_size : 패킷 첫번째 배열에는 항상 그 패킷의 데이터 사이즈가 저장되어있음..
그 패킷의 ㄹㅇ 사이즈
data_size : 여태 받은 데이터의 총 길이..
패킷을 완벽히 처리 받으려면.. packet_size<=data_size 인지 비교해야함.
p는 현재 패킷의 시작위치.. 거기서 +packet_size 해가면서 p라는 포인터를 옮겨주는거
아무튼 혹시라도 데이터가 덜온거라면... _remained에 그 크기만큼 저장시켜두고 다음 리시브때 마저 해준다고함.
아직 미완성이라... process_packet까지 하고 다시 올리도록 하ㅁ.
'서버' 카테고리의 다른 글
일대일서버정리 (0) | 2025.04.06 |
---|---|
서버 2w1(네트워크프로그래밍) (0) | 2025.03.18 |
서버1w2 (0) | 2025.03.18 |
서버1w1 (0) | 2025.03.14 |