서버와 클라이언트의 연결을 기다리는 용도의 Listener 클래스는 시작점인 Init, 기다리는 연결이 바로 실행될 수 있음을 확인하는 RegisterAccept, 연결 완료를 담당하는 OnAcceptCompleted, 연결을 받아들이는 Accept 함수로 구성된다.
Socket _listenSocket;
Action<Socket> _onAcceptHandler; // Accept가 완료됐을 때 어떻게 처리할 것인지 담당.
public void Init(IPEndPoint endPoint, Action<Socket> onAcceptHandler)
{
_listenSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
// AddressFamily == 네트워크 유형, Stream / Tcp == TCP 사용을 위한 설정
_onAcceptHandler += onAcceptHandler;
_listenSocket.Bind(endPoint); // 소켓 정의
_listenSocket.Listen(10); // 연결 요청 대기. 최대 대기 수 10
SocketAsyncEventArgs args = new SocketAsyncEventArgs();
// args 비동기 작업이 완료됐을 때(Compledted) 새로운 이벤트인 OnAcceptCompledted를 콜백방식으로 불러오자.
args.Completed += new EventHandler<SocketAsyncEventArgs>(OnAcceptCompleted);
RegisterAccept(args);
}
Init은 endPoint와 onAcceptHandler를 인자로 받게 된다. onAcceptHandler는 말 그대로 Accept의 완료 처리를 담당한다. Init에서는 소켓을 정의하고, 기본적인 환경을 설정한다. _onAcceptHandler와 onAcceptHandler를 연결하는 +=는 델리게이트 체인이다. onAcceptHandler는 콜백 이벤트로 설정해주고 RegisterAccept(args)를 통해 연결을 기다리는 대기자 수를 확인하게된다.
void RegisterAccept(SocketAsyncEventArgs args)
{
args.AcceptSocket = null; // 이벤트 재사용 시 기존 이벤트를 날려주고 실행하는 게 중요.
// pending == 대기자수 체크.
bool pending = _listenSocket.AcceptAsync(args); // 비동기 함수 사용 예약하기.
if (pending == false) // 너~무 한가해서 대기자 수 하나도 없고 바로 비동기 함수 실행됨.
OnAcceptCompleted(null, args);
}
확실한 초기화를 위해 기존 이벤트를 날려주고 pending을 통해 대기자 수를 체크한다. *pending이 false라면 바로 OnAcceptCompleted를 실행해준다.
* 비동기방식으로 Accept를 요청했는데 true 값이 반환된다는 건 비동기적으로 콜백 함수를 사용한다는 뜻이지만 false가 반환된다는 건 동기 방식으로 바로 Accept가 진행된다는 의미다.
void OnAcceptCompleted(object sender, SocketAsyncEventArgs args)
{
if (args.SocketError == SocketError.Success)
{
// Socket clientSocket = _listener.Accept();를 해주는 부분.
_onAcceptHandler.Invoke(args.AcceptSocket);
}
else
Console.WriteLine(args.SocketError.ToString());
RegisterAccept(args); // 난 다 끝났고, 다음 아이를 위해서 다시 예약
}
public Socket Accept()
{
return _listenSocket.Accept();
}
OnAcceptCompleted는 확실하게 연결이 진행됐을 경우 호출된다. SocketError를 확인해서 연결이 성공했다면 _onAcceptHandler를 Invoke해서 소켓을 허용한다. 이는 Socket clientSocket = _listener.Accept()와 같은 의미다. 연결이 실패할 경우 에러 메시지를 출력한다. 그리고 다시 다음 아규먼트를 RegisterAccept에 연결한다.
'공부 > 게임 서버' 카테고리의 다른 글
[게임 서버] SetBuffer를 RecvBuffer, SendBuffer로 따로 빼내기 #2 (0) | 2022.06.21 |
---|---|
[게임 서버] SetBuffer를 RecvBuffer, SendBuffer로 따로 빼내기 #1 (0) | 2022.06.20 |
[게임 서버] Listener의 반대 개념, Connector에 대해서 (0) | 2022.06.20 |
[게임 서버] 소켓 프로그래밍 BufferList를 사용하여 한 번에 Send (0) | 2022.06.18 |
[게임 서버] 아주아주 간단하게 만드는 소켓 프로그래밍 환경 (0) | 2022.06.17 |