패킷 모아보내기

CJB_ny·2022년 3월 6일
0

Unity_Server

목록 보기
50/55
post-thumbnail

우리가 지금까지 Job Queue에 대해서 알아보았다.

그리고 지금

이 GameRoom이라는 개념이 굉장히 중요하다.

던전, 마을에 이런 Room이라는 개념이 들어갈 수 있을 것이다.

그게 아니라고한다면 이게 필드에 있는 하나의 "Zone"이 될 수도 있다.

그래서 이런 Zone에 유저들이 많이 모여있고

그 유저들이 어떤 행동을 하는 것들을

BroadCast를 통해

전체로 == foreach로 뿌려주는

이런 작업이 결국에는 "온라인" 게임이라고 생각하면된다.

지금은

이런 간단한 채팅패킷만 보내고 있었지만

이동하는 패킷, 공격하는 패킷등을 뿌려주는 작업을 계속 하다보면은

그게 그냥 온라인 게임이다.

나중에 클라쪽에서는

이렇게 받은 정보를 유니티에서 렌더링 해가지고

player가 이동했다면 그 좌표만큼 이동해주고

그런식으로 시간을 "서버"랑 맞춰서 구현을 하면은

굉장히 그럴싸하게 돌아가게 될 것이다.


그런데 지난 시간에 이야기 한것처럼

이렇게만 구현을 하면 굉장히 큰 문제점이 있다.

여기 있는 부분이 굉장히 부담이 된다고 했었다.

이부분이 부화가 심해서 packet을 모아 보내야 한다.

그래서

Session > Send 가보면은

Engine딴에서 한다는 것은 어떤 의미냐? 하면은

이렇게 Send를 한다고 했을 때 _pendingList.Count가 0이면은

바로 이어서 보내는 작업을 했는데

사실은 이렇게 Enqueue하는 작업이랑 RegisterSend == 보내는 작업이랑 분리를 해가지고

어느정도 쌓였을때 모아보내면 그게 "패킷 모아보내기"이다.

그리고 Engine딴에서 그 작업을 하는게 아니라

Contents딴에서 하는것도 가능하다.

즉,

GameRoom에서 구현을 하는것도 가능하다.

우리는 컨텐츠 딴에서 모아보내는 방법을 살펴보도록 하자.

다시말하지만 이것을 구현을 하는것은 굉장히 간단하다!

그래서

GameRoom >

이렇게 리스트를 만들어서

보낼 segment를 그냥 List안에다가 넣어두는 작업만 하도록 하자.

그래서

모아서 보내는데 그 모아서 보내는 녀석은 누군가가 해야하기는 하는데

GameRoom을 관리를 하는 녀석이 0.1초마다나 아니면 0.25초마다 그

작업을 해주게 된다.

그래서

Server > Program의 Main 으로 돌아와가지고

지금 Main쓰레드는 아무일도 안하고 서브쓰레드들한테

모든 일감을 맡기고

while문안에서 그냥 뺑뺑이를 돌고만 있었다.

그래서

이렇게 while문 안에서

0.25초마다 Flush를 하도록 만들어주자.

그리고 GameRoom에서 Flush라는 함수를 만들어 주면된다.

그래서 이렇게 되는 것이다.

그런데 이제는

이 segment를 보내는게 아니라 이때까지 모아두었던

_pendingList에 쌓여있는 것들을

이렇게 보내주면된다.

(지금은 넣어주는 함수를 안 만들어서 빨간줄 뜬다 -> 만들면됨 )

이렇게 로그를 찍어주도록 하고

여기서도 보면은 락을 안잡고있었다.

왜냐하면 실제로 잡큐에서 일감을 넣거나 뺄때

락을 잡고 한명만 하도록 하였기 때문에

Flush도 한명만 사용할 것이라는 보장이 되어서 락을 안 잡은 것이다.

이것은 굉장히 어려운 개념이다.

(ㅅㅂ.. 이해가 잘 안간다)


아무튼 그다음

이 Send라는 애를 Session쪽에다가 만들어 줘야 한다.

그래서 ArraySegment를 받는 Send를 하나 더 파주면되는데

이렇게 List를 받는 Send를 만들어 주고 안에서는 똑같이

foreach를 돌면서 Enqueue를 해주는 부분까지 같고

if 문도 1빠로 왔다면 RegisterSend하는 부분까지 같다.

그리고 이렇게 하나만 체크 ㄱㄱ.

이거 안넣어 주면

빈 상태로 값을 넘겨주게되는데

그렇게되면은

일로 넘어와서

OnSendcompleted하게 되고 >

여기서 연결을 끊어버리는 슬픈일이 발생할 것이다.

(첫번째 if문에서 인자가 잘못되어서)

그래서 테스트 해보면

100개씩 잘보내고 있기는 한데

가끔가다가 일감이 밀려서 200개씩 보낼때도 있다.


그리고 지금 클라쪽에서

뭐 몇개를 받고있는지 추적이 안되니까 추적을 하기 위해서

Session >

OnRecv에서

만들어주고

OnRecvPacket까지 왔다면 packetCount가 늘어난 것이니까

늘려주자.

그리고 밑에서 로그를 찍도록 해주고

몇바이트를 받는지는 주석처리를 하고 실행을 해보면

서버에서는 100개의 패킷덩어리를 보냈는데

받는쪽 == 클라쪽에서는

100개를 못받고있다!

문제

이런일이 일어날 수 있는 가장 큰 이유중 하나는

BufferSize가 너무 작어서 그럴 수가 있다.

그래서 ServerCore > RecvBuffer >

여기서 처음에 만들때 사이즈를 받아주고 있었다.

그렇다는 것은 RecvBuffer를 너무 작게 해주었다면은

분명히 문제가 일어난다는 얘기가된다.

RecvBuffer를 사용하고있는것은

Session.cs >

여기서 사이즈를 1024로 굉장히 작게 해놓았었다.

그러면 이녀석을 우리가 받을 수 있는 최대 사이즈

65535로 맞춰 주도록 하겠다.

그리고 SendBuffer도 마찬가지로 ㅈㄴ 크게

이렇게 해주도록 하자.

그리고 테스트 ㄱㄱ

하면 둘다 100개씩 보내고 잘 받고있다.

그래서 아까보다 효율이 100배이상 좋아진 것이다.

그래서 어떤 방식으로든 패킷 모아보내기가 구현이 되어야지만

MMO에서 정상적으로

packet을 버틸 수 있다는 얘기이다.

이것이 진짜 중요한 개념이다


그리고 궁금하니까

숫자를 늘려서도

해보면 이렇게 보내진다.

프로세스 메모리도 어느정도 선에서 유지가 되는 것을 볼 수 있다.

그런데 이렇게 같은 공간안에 500명씩 모여있는 경우는 거의 없을 것이다.

그래서 어느 한 구역에 엄청 많은 유저들을 모아놓고

하는것은 부화가 심해 구현하기 굉장히 어렵다.


그리고 지금 GameRoom에서

에코서버 느낌으로 별다른 작업을 안하고

모아서 보내는 정도를 하고있었는데

GameRoom에서 이제 다른 다양한 작업이 들어 갈 것이다.

GameRoom안에 몬스터가 있는데

몬스터도 움직일 테고

몬스터도 길찾기를 사용하여 스킬도 한번씩 써주고 이런 것을 할텐데

그런 작업들도 같이 들어가게 될 것이다.

그렇다는 것은 이 GameRoom을 실행시키는 별도의

"Master"가 있어야 한다는 것이다.

그래서 보면은

Server > Program > Main쓰레드가

Flush를 하는 역할을 메인쓰레드가 맡아서 하고있었는데

반대로 얘기하면은

서버도 클라와 마찬가지로

누군가가 주기적으로 업데이트를 해가지고

해당공간이나 객체를 갱신해주는 작업은 당연히 들어가야한다.

클라같은 경우에는 각각 컨트롤 하고있는 클라PC에서

게임하고있는 사람이 걔내들이 관리를 할텐데

그게 아니라 몬스터, NPC 등등은 서버에서 다 담당을 해가지고

연산을 해주어야 한다.

그래서 이렇게 Flush를 한것 외에도

로직을 실행시키기위해서는

서버의 어디선가 그 로직을 실행하는 부분이 있어가지고

GameRoom공간 안에서

유저들이 보낸 패킷외에도 AI든 뭔든

여기 _jobQueue에다가 밀어넣어서

"같이"실행을 시켜줘야 한다는게 결론이 되겠다.

profile
https://cjbworld.tistory.com/ <- 이사중

0개의 댓글