이번 시간에 할 내용 요 : 지난 시간에 Server 쪽 작업을 했으니 오늘은 클라쪽 작업을 함.
요약:
1. DummyClient에 SessionManager 클래스를 추가하여 여러 개의 ServerSession을 관리할 수 있게 함.
2. DummyClient의 Program에서 Connect를 호출할 때, SessionManager를 이용해 생성한 Session을 전달하고 Connect 횟수를 조정할 수 있도록 함.
3. DummyClient의 ServerSession을 정리하고, OnRecv를 OnRecvPacket으로 변경. PacketManager를 이용해 패킷을 처리함.
4. Program에서 SessionManager를 이용해 패킷을 전송하도록 수정하고, 서버로부터 받은 패킷을 처리하는 PacketHandler를 수정.
5, 서버의 Program에서 Register 호출 부분을 삭제하고, PacketManager를 싱글톤으로 변경하고, 생성자에서 Register를 호출하게 한 후, PacketFormat을 수정해 자동으로 수정되도록 함.
6. 테스트 결과, 각 playerId마다 10번씩 출력되는 것을 확인함.
7, 문제점: 1초에 40,000번 뿌리는데 락 때문에 처리가 밀림.
8. 해결책: GameRoom을 실행하는 애는 한 명만 실행되게 하여, 일감을 큐에 넣고 빠져나와 실제로 큐를 실행해 처리하는 애는 한 번만 작동하게 함. 패킷이 온 행위를 미루어 나중에 처리하게 함.
1. DummyClient에 SessionManager클래스 추가
1.1. SessionManager생성 이유
→ 지금은 DummyClient의 Program에서 Connect 를 한번 해서 ServerSession이 1개만 생성되고 있지만 여러개를 만들어서 실험을 해보기 위해 SessionManager에서 관리하면 편할 거 같아서
1.2. Server의 SessionManager와 다른 점
1.2.1. Id 관리 안함
1.2.2. Dictionary대신 List 사용
1.3. 비슷한 점
1.3.1.static으로 SessionManager _session 생성하고, Instance로 전역으로 _session사용
1.3.2.List로 _session들 들고 있게 함.
1.3.3.락할 때 쓸 object 생성
1.3.4.Generate인터페이스 만들기
a. ServerSession session을 생성하고
b. _sessions에 Add하고
c. session을 return
2. DummyClient의 Program에서 Connect를 호출할 때 매개변수로 Session을 SessionManager를 이용해 생성해 전달
3. Connect의 횟수를 조정할 할 수 있게 ServerCore의 Connector의 함수 Connect의 매개변수 int count를 추가
4. DummyClient의 ServerSession을 정리
4.1. OnConnected에 있던 실험용 코드를 삭제
4.2. SeverSession클래스가 Session을 상속받고 있는 거에서 PacketSession을 상속받게 바꿈
4.3. OnRecv를 OnRecvPacket으로 바꿔주고, 구현부는 PacketManager를 Instance를 호출해 생성하고, OnRecvPacket을 실행(싱글톤)
4.4. OnSend부분의 메시지를 주석처리
5. Program에서 SessionManager를 이용해 패킷을 쏘게 수정
5.1. while의 try 에 SessionManager를 Instance로 생성하고 SendForEach를 호출
5.2. SessionManager에 SendForEach를 정의
a. 락을 걸고 모든 foreach로 _sessions를 순회한다.
b. C_Chat을 생성하고 chat에 문자열을 넣는다.
c. wirte로 byte형 ArraySegment를 추출한다.
d. session.Send에 추출한 segment를 넣어 보낸다.
6. Server로 부터 받은 Packet을 핸들링하는 DummyClient의 PacketHandler를 수정
6.1. 함수를 S_ChatHandler로 바꿈
6.2. packet을 as S_Chat으로 추출하고, session도 ServerSession으로 추출한 다음에 packet의 내용을 출력
6.3.playerId가 1인 경우만 출력하게 함
7. Server의 Program에서 Register를 호출하면 까먹을 위험이 있으니 수정한다.
7.1. Server의 Program의 Main에서 Register하는 부분을 삭제
7.2. ServerPacketManager를 Instance를 사용하는 싱글톤으로 바꿔주고, 생성자에서 Register를 호출
7.3. PacketGenerator의 PacketFormat의 PacketManager부분을 수정된 버전으로 바꿈
7.4. PacketGenerator를 빌드하고 GenPacket.bat을 실행
7.5. ClientPacketManager도 자동으로 변경 된 것을 확인
8. 테스트
8.1.DummyClient창에서 Hello Server가 뜸
8.2.DummyClient의 PacketHandler에서 playerId가 1일때만 출력되는 조건을 삭제
8.3.Server의 GameRoom의 Broadcast에서 Client로 보내는 메시지의 내용을 playerId도 출력하게 수정
8.4.실행하면 각 playerId마다 10번씩 출력이 됨
9. 문제점 파악, 개선점
DummyClient의 Program에서 Connect의 인자 count의 수를 100으로 수정해 테스트
9.1.GameRoom의 Broadcast의 Locak에 breakpoint를 잡고 실행
9.2.스레드가 들어나서 breakpoint에 멈춰 있다. main thread만 Server의 Program에 멈춰있는 걸 알 수 있다. 원인을 찾아 보면, breakpoint에 멈춰있는 thread중 하나의 callstack을 보면 OnRecvPacket→MakePacket→ C_ChatHandler→Broadcast 순서로 실행되고 있는 걸 알 수 있음
9.3.문제의 원인 - 0.25초마다 100명이 보내는 걸 받아서 Broadcast해주고 있는건데 Broadcast에 lock을 걸어 0.25초 마다 100명에게 뿌리고 있다. 즉 1초에 40000번 뿌리고 있는거. 락을 걸고 하는 거라 한번에 1개씩 처리 하기 때문에 밀리게 됨
9.4.해결책- GameRoom을 담당해서 실행하는 애는 한 명만 실행되게끔 만들어줘야 됨.
일감을 그냥 큐 에다만 넣고 빠져나오고 볼일을 보러 간 다음에 실제로 큐를 실행해가지고 실행하는 애는 한 번만 작동하게 함. 중요한 것은 어떤 일감을 패킷이 왔다는 행위 자체를 뭔가 랩핑해서지고 그 행위를 나중에 한 애가 여유가 될 때 처리하게끔 미루는게 핵심
'Server programming' 카테고리의 다른 글
04_04_JobQueue_JobQuene#1 (0) | 2023.05.07 |
---|---|
04_03_Job Queue_Command 패턴 (0) | 2023.05.05 |
04_01_Job Queue_채팅 테스트 #1_서버 (0) | 2023.04.25 |
03_11_패킷 직렬화_PacketGenerator #6_PacketManager 코드 생성을 자동화, 패킷 분리 (0) | 2023.04.20 |
03_10_패킷 직렬화_PacketGenerator #5_ switch문의 비효율성 개선, case 파싱 자동화 (0) | 2023.04.20 |
댓글