Accept, Receive의 비동기 처리까지 완료하고, send를 비동기 처리하는 작업을 하였다. 하지만 아직 효율적이게 개선이 완료된 것이 아니기에 오늘도 이어서 개선해나아갈 예정이다.
_sendArgs는 버퍼 사이즈 설정 이슈로 receive 처럼 새로 생성하고 반복 사용하는 것이 안되기 때문에 멤버 변수로 선언하고 사용하였다.
이때 recvArgs는 이렇게 지역변수로 생성해주어도 되지만, C++과 구조를 유사하게 맞추기 위해 함께 멤버변수로 선언을 해주어도 상관이없다.
기존에는 SocketAsyncEventArgs를 매개변수로 받아 처리하던 부분을 지우고, 이렇게 직접 넘기는 방식으로 수정해주면 된다.
지난 시간에 작성한 코드를 보면 Dequeue를 통해 배열을 하나씩 뽑아 담아주는 방식을 사용하고있다.
이때 하나씩 처리하는 것이 아닌 담긴 정보를 통채로 넣을 수도 있다.
이 친구는 이름에서도 얼추 알 수 있듯이 List형태로 한 번에 담을 수 있는 구조를 가지고있다. 하지만 사용법이 조금 특이하다.
ArraySegment< T >
배열의 일부분이라는 뜻으로 ArraySegment(원하는 배열, 시작 인덱스, 길이)를 설정해주면 원하는 배열 내에서, 시작 인데스부터 길이 만큼을 복사해서 사용할 수 있게 해준다.
잘못된 BufferList.Add의 예시
_sendArgs.BufferList.Add (new ArraySegment<byte>(buff, 0, buff.Length));
다만 위와 같이 BufferList.Add에 직접적인 방법으로 넣을 경우 오류가 발생할 수 있어 List에 담은 후, 그 List를 BufferList에 담아야한다.
위와 같이 _pendingList라는 것을 따로 제작하여 여기에 Add하는 방식으로 담고, 그걸 한 번에 BufferList에 담아준다.
while을 통해 Queue에 담겨있는 buff를 한 번에 담아 처리하면 더 빠르게 동작할 수 있을 것이다. TLS 할 때 배웠던 일감을 여러개 들고 가서 처리하는 것과 비슷한 느낌이다.
현재까지 _pending이라는 bool 값을 통해 처리할 것이 남아있는지, 처음 접근하는지를 파악하였다. 하지만 이제 _pending List가 있으니 이를 활용하면 된다.
현재 동작 중인 작업이 없는지를 체크하고, 다음 단계로 넘겨주기 위한 체크였는데, 이를 _pendingList.Count의 개수를 체크하는 조건으로 변경한다.
여기는 들어오자마자 문을 닫아주기 위해 true 처리해주었는데, queue는 이보다 빨리 Count가 증가되어 이제 필요가 없으니 제거해주자
모든 작업이 성공한 뒤에 들어오는 해당 메소드에서는 BufferList와 _pendingList를 모두 초기화 해준다. buffer의 경우는 굳이 해줄 필요 없지만 깔끔함을 위해 해주었다.
이렇게 까지하고 테스트해보면 잘 작동하는 걸 확인할 수 있다.
한 번에 보내서 처리하는 방식은 좋으나, 이렇게 할 경우 엄청나게 많은 패킷이 계속 지속될경우 문제가 발생할 수 있어 한 텀 쉬어서 가는 것이 좋다.
이럴 때는 Receive하는 부분에서 너무 이상하게 많이 오거나, 자주 오는 부분을 Disconnect 해주는 방식으로 처리할 수 있다.
실시간 게임에서는 유저가 살짝이라도 움직이는 걸 1,000명이 넘는 다른 유저들에게도 공유해주어야 한다. 그때 작은 단위로 buff를 보내는게 아니라
엄청나게 큰 버퍼를 만들어 그걸 날려주는 방법이있다. 그건 서버에서 처리하거나, 보내줄 때 처리하기도 하는데 정책을 정하기 나름이다.