TCP 소켓 통신을 공부하다가,
유니티 클라이언트가 먼저 종료될 때,
서버가 먼저 종료될 때,
각각의 케이스에 대해 Noti 를 줄 수 있게 disconnect 에 대한 처리를 하고 싶었다.
서버에서는 클라이언트를 Listener 객체 하나가 반복적으로 감지를 하고 있으므로,
Client 쪽에서 socket 이 Close() 되었을 때,
ByteTransferred 가 0 일 경우에 Disconnect 로 보고 분기를 처리할 수 있었다.
private void ProcessReceive(SocketAsyncEventArgs receiveArgs)
{
NetLog.Log("Process Receive...");
UserToken token = receiveArgs.UserToken as UserToken;
// 받은 데이터가 있고, Success 일 경우
if (receiveArgs.BytesTransferred > 0 && receiveArgs.SocketError == SocketError.Success)
{
token.ProcessReceive(receiveArgs.Buffer, receiveArgs.Offset, receiveArgs.BytesTransferred);
bool pending = token.GetSocket().ReceiveAsync(receiveArgs);
if (pending == false)
{
ProcessReceive(receiveArgs);
}
}
else
{
NetLog.Error($"SocketError {receiveArgs.SocketError} / BytesTransferred : {receiveArgs.BytesTransferred}");
DisconnectClient(token);
}
}
여기서 실제로 Client 를 종료시켜보면 else 분기를 타는데,
문제는 SocketError 가 Success 로 찍힌다.
SocketError 의 열거형을 보면
이렇게 다양한 것이 있는데, 그 중 Disconnecting 도 아니고 왜 Success 로 오는지가 어색했다.
GPT 에게 물어보았다.
SocketError 는 말 그대로 오류가 생길 경우에만 Success 이외의 것으로 반환되는 것 같았다.
추가로, BytesTransferred 값이 0 이라는 것은 정상적으로 연결이 끊겼다는 의미라고 한다.
이 부분을 처음 알았다.
즉, 코드를 수정하면
private void ProcessReceive(SocketAsyncEventArgs receiveArgs)
{
NetLog.Log("Process Receive...");
UserToken token = receiveArgs.UserToken as UserToken;
// 받은 데이터가 있고, Success 일 경우
if (receiveArgs.BytesTransferred > 0 && receiveArgs.SocketError == SocketError.Success)
{
token.ProcessReceive(receiveArgs.Buffer, receiveArgs.Offset, receiveArgs.BytesTransferred);
bool pending = token.GetSocket().ReceiveAsync(receiveArgs);
if (pending == false)
{
ProcessReceive(receiveArgs);
}
}
// 정확한 디스커넥트 시점
else if (receiveArgs.BytesTransferred == 0)
{
NetLog.Log($"SocketError {receiveArgs.SocketError} / BytesTransferred : {receiveArgs.BytesTransferred}");
DisconnectClient(token);
}
else
{
NetLog.Log($"SocketError {receiveArgs.SocketError} / BytesTransferred : {receiveArgs.BytesTransferred}");
}
}
else if 로 Bytestransferred 가 0 인 경우만 분리해서 Disconnect 에 대해서만 처리할 수 있다.
else 를 모두 싸잡아 disconnect 로 간주하던 부분이 찝찝했는데 해결되었다.
물론, GPT 가 조현병 증상으로 거짓말을 한게 아니라면 말이다. 일단, 믿기로 했다..
문제는 이제 서버가 먼저 종료될 경우에 클라이언트에서 감지하는 부분이다.
MMO 게임을 하다보면, 서버 점검등이 이루어질 때, 정각이 되면 유저들에게 팝업이 뜨고 모두 튕기는 상황이 생긴다.
이런 상황을 구현하고 싶었다.
서버 측에서, 접속한 유저 Token 을 가지고 있다가, 서버 종료 시점에 유저리스트를 순회하면서
강제로 socket 을 종료시켜주었다.
하지만 클라이언트에서 이를 감지하기 위해서는 새로운 요청을 전송할 때가 오기 전까지는 감지할 수 없었다.
원래 이런건지 GPT 에게 물어봤다.
정상적인 과정이 맞는 것 같다.
++ 회사에서 베테랑 분께 여쭤보니 맞다고 한다~
하트비트같은 기법을 사용하라고 하셨다
'게임 서버(TCP)' 카테고리의 다른 글
게임 서버 입문해보기 1 - 유니티 개발자를 위한 C#으로 온라인 게임 서버 만들기 (0) | 2024.10.14 |
---|