지난 시간에 Send를 조금 효율적으로 고치는 방법에 대해서 알아보았다.
이게 무슨 말이냐 하면은
패킷을 보내고 싶을때
를 통해서 보낼 수 있다.
패킷을 받는 경우에
이런식으로 콘솔에다만 찍고 아무것도 안하고 있었다.
그래서 여기다가 콜백으로든 어떤 방식으로든 메세지를 받았다는 것을 연동을 시켜줘야되는데
사실은 이런 비슷한 작업을 Listener.cs에서도 하고있었다.
Listener는 Socket을 받는 Action을 하나 만들었었다.
init에서 이녀석을 받아서
실제로 클라가 접속을 했을 떄
AcceptAsync가 완료가 되었을 때
_onAcceptHandler.Invoke(args.AcceptSocket);
이런식으로 콜백방식으로 알려줬었다.
그거를 이제 Program에서
이렇게 등록을 해가지고
처리를 하고있었다.
그래서 Session도 그런 작업을 해줘야한다.
그래서 Session에 뭐가 필요한지 생각해보면
Session은 ServerCore에 들어가 있는 녀석이다.
그런데 ServerCore는 말그대로 Core 라이브러리 이다.
서버엔진같은 존재라서
나중에 컨텐츠는
이 Server쪽에다가 만들게 될텐데
그때는 Session을 바로 사용하는게 아니라
뚫어준 인터페이스로 작업을 하게 될 것이다.
그래서 이벤트를 받아주는 방식을 어떻게 할것이냐 하면은
두가지 방법이 있는데
1) EventHandler를 만들어서 연결하는것
2) Session을 상속을 받아서 만드는 방법
이렇게 크게 두 가지인데
크게 필요한 부분이 네가지가 있으면 좋을 것이다.
이런식으로 인터페이스만 맞춰 주는데
public void OnConnected(EndPoint endPoint) { }
클라가 접속을 완료를 했다 == 접속을 했다가 첫번째
인자는 endPoint를 받으면 좋을거같다=> 어떤 IP주소에서 접속을 했다라고 로그를 남길 수도 있으니까
public void OnRecv(ArraySegment<byte> buffer) { }
-> 클라 쪽에서 패킷을 보내서 내가 받았다라는 메세지가 올텐데
받는것은 byte[]로 해도되고 이전에 배웠던 Segment해도 노상관
(물론 나중에는 패킷이라는 개념으로 받음)
public void OnSend(int numOfBytes) { }
public void OnDisconnected(EndPoint endPoint) { }
그래서 크게 이런 네가지 동작을 뽑아서 사용을 할 것이다.,
그래서 나중에 외부에서 이 Session을 사용을 할때는
이런부분만 사용을 할 것이지
실제로 내부의
이런 동작들은 관심도 없을 것이다.
그래서 이것들을 어떻게 처리를 하느냐?
이렇게 넣어주고
이렇게 사용하는게 첫번째 방법일 것이고
아니면 상속을 받는다고 했었는데
상속을 받는게 구현하기 쉽기때문에
상속을 받도록 하겠다.
그래서 abstract로 수정을 해준다.
이제 Session은 바로 사용할 수없고
이런식으로 상속을 받아서 사용을 해야된다는 의미이다.
그래서
이녀석들을 이제 연동을 해주면된다는 것이다.
그리고
abstract클래스는 막바로 사용할 수 없으니까
무조건 상속받은 GameSession으로 만들어야된다.
그다음에
이제 이녀석들 하나둘 연동을 해줘야함
가장 간단한 DisConnect부터 해보면
여기서 호출만 해주면되는데
그 녀석을 받아가지고 하고싶은 일이 있다면
여기서 뭘 하면됨.
그다음 중요한게 Send,Recv 있는데
가장 중요한게 Recv라 이것부터 하자
여기서 이제 하드코딩된 메세지만 출력하고 끝낼게 아니라
이제 TODO
TODO를 이렇게 채워주면될 것이다.
그리고 아까 삭제했던 부분은 이사를 시켜주도록 하겠다.
여기에 이사띠!
그리고 인터페이스 맞춰준다!
아까랑 기능은 같은데 ArraySegent로 넣어 주었기 때문에...
결국에는 OnReceiveEvent가 발생했을 떄 이제는
여기닥 즉, 컨텐츠 코드에 넣어주게 되는 것이다.
그래서 우리가 하는 작업은 뭐냐
"엔진"과 "컨텐츠"를 분리를 하기 시작하는 것이다.
그래서 나중에는
이런 GameSession을 만들어서 각자 사용을 할 것이고
그리고 Session에서는 뭘 할지는 모르지만 이벤트만 이렇게 호출을 해주는 식이다.
이부분에서 이제 바꿔치기를 해줄 것이다.
이렇게 해주고 콘솔찍는 부분은 이사를 시키자.
이렇게!
이녀석도 마찬가지로 이제 컨텐츠코드에서 실행을 하도록 "분리"를 하고있는 것이다.
얘도 이렇게 수정.
그러면 이제다시 Session으로 와보면은
OnConnected가 안되어있는데 이녀석은 생각해보면 조금더 까다롭다.
이녀석을 알리는 시점은 클라가 접속을 했을 때! 그 시점인데
이녀석 같은 경우에는 listener에서 해주고 있었다.
여기서 에러없이 들어오고
여기서 뭔가를 해줘야 되는데
우리가 세션을 만들어서 이벤트를 보내주는 작업을 Listener에서는 Handler로 하고있었다.
이렇게 OnAcceptHandler라는 애를 만들어서 연결을 해주고 있었다.
이렇게 해도 크게 잘 못된것은 아니기는 한데
지금은 Session이라는 개념이 만들어 졌으니까
이 녀석은 컨텐츠쪽으로 빠져 있는 것이다.
서버엔진에서는 OnAcceptHandler를 관리를 하는게 아니라
우리가 처음에 _listener를 초기화를 할때 어떻게 어떤 방식으로 처리를 할지를 OnAcceptHandler로 만들어 주고 있었는데
Start하는 부분은 컨텐츠딴보다는 엔진딴에 들어가있는것이 조금더 맞는거 같은 생각이 든다.
그렇다는 것은
이렇게 하는게 아니라
이부분을 일단 엔진쪽으로 옮겨 보도록 하겠다.
session을 만들고 Start하는 부분까지
이렇게 옮긴다.
여기서 이제 Invoke를 할게 아니라
이렇게 해주면 된다.
이렇게하면 Start하는 부분이 외부에 노출되지 않기 때문에
관리 차원에서는 더 좋을 것이다.
그런데
GameSession을 여기 안에서 만들어주는게 문제가되는데
왜냐하면 게임에 따라서
이게 이름이 GameSession이 아니라
MMO_Session이런식으로도 될 수 잇는데
여기서 강제로 만들어 주고 있기 때문에
밖에서 위음을 하거나 밖에서 정의를 해주는 것이 맞다.
그래서 이게 아니라
이렇게 어떤 방식으로 누구를 만들어 줄지 정의를 하는 녀석이다.
Action과 다르게 Func는 result타입이 있는 녀석이다.
함수를 만들때 이제는 인자는 아무것도 안받고 뱉어줄때는 session이라고 뱉는 함수 형식을 만든 것이다.
init에서 인자를 이녀석으로 받고
이렇게 연결을 해줄 것이다.
그러면 이제
여기서 OnAcceptHandler를 받는게 아니라
여기서는 session을 누구를 어떻게 만들지 정의를 해줘야 된다는 말이다.
우선은 람다로 정의를 하도록 하겠다.
이렇게 해주면된다.
아까와 조금다른데
컨텐츠 딴에서 뭔가를 하기는 하는데
이런식으로
전체적인 처리 (특히나 Session.Start()와 같은 중요한 부분)들을 외부에서 (== 컨텐츠에서) 처리를 하는게 아니라
무엇을, 어떤 세션을 만들지만 결정을 해주고
나머지 부분은
이런식으로 안에서 다 해주고있다는 것이다.
그러면 OnConnected를 호출을 해줬으니
이제 GameSession에서
여기서 이제 뭔가 시작할 코드를 넣어주면 된다.
그리고
우리가 이런부분을 컨텐츠 코드에서 하고있었으니까
복붙해서 여기 넣어주자.
그리고
지금 GameSession자체가 Session이니까 == 상속 받았으니까
이렇게 해주면된다.
그리고 이녀석은 이제 필요없으니 삭제를 해주자.
그리고 중간에 뺴먹은 부분이
힘들게
_sessionFactory를 받은 이유는
이부분인데 new를 하지않고
이렇게 해주기 위해서였다.
그리고 _sessionFactory는 어떤 session 타입인지 모르니까
가장 상위인
Session으로 뱉어주고 잇었으니까
이렇게 Session으로 수정을 한다.
일반적인 상황에서는 다 Session을 상속 받을 테니..
이렇게해서
엔진과 컨텐츠를 어느정도 분리를 했는데,
테스트를 해보면 지금까지는 잘 작동을 한다.
나중에 코드가 더 많이지면 알겠지만
몇가지 문제사항이 있기는 하다.
예를 들면 이부분에서 AcceptSocket에서 RemoteEndPoint를 추출을 해서 사용을 하고있는데
만약에
여기 들어온 순간
여기서 OnConnected로 넘어가는 순간에
클라쪽에서 연결을 끊어버리면
args.AcceptSocket에 접근하는게 허락이 되지 않는다.
그래서
이부분에서 에러가 날꺼긴 하다.
이부분은 나중에 코드를 테스트를 해보면 다 걸리게 된다.
서버를 만들때는 하나하나 테스트를 해보면서 방어를 하듯이 코드를 넣는게 좋다.
그래서 오늘은 분리를 하는 간단한 작업을 해보았다.