[C#][Server] 6. Listener와 Session 구조의 리팩토링
C# Socket Programming TIL: Listener와 Session 구조의 리팩토링
1. 진행 상황
Listener클래스에서 세션 생성을 동적으로 처리하도록 구조를 리팩토링하였다.- 기존의
Action<Socket>방식 대신Func<Session>을 사용하여,Listener와Session간의 의존성을 줄이고 확장성을 높였다. Session클래스에 다음과 같은 네 가지 새로운 메서드를 추가하여 네트워크 이벤트를 처리할 수 있도록 개선하였다:OnConnected(EndPoint endPoint)OnRecv(ArraySegment<byte> buffer)OnSend(int numOfBytes)OnDisconnected(EndPoint endPoint)
2. 주요 변경 사항
1) Listener 클래스
변경 전:
기존에는 Listener 클래스가 소켓 연결을 처리할 때, Action<Socket> 델리게이트를 통해 클라이언트 소켓을 단순히 전달하였다.
Action<Socket> _onAcceptHandler;
public void Init(IPEndPoint endPoint, Action<Socket> onAcceptHandler)
{
_onAcceptHandler += onAcceptHandler;
_listenSocket.Bind(endPoint);
}
// 클라이언트 소켓을 직접 전달
_onAcceptHandler.Invoke(args.AcceptSocket);
변경 후:
Func<Session>을 활용하여 세션 객체를 동적으로 생성하도록 변경되었다.
Func<Session> _sessionFactory;
public void Init(IPEndPoint endPoint, Func<Session> sessionFactory)
{
_sessionFactory += sessionFactory;
_listenSocket.Bind(endPoint);
}
// 세션 생성 및 초기화
Session session = _sessionFactory.Invoke();
session.Start(args.AcceptSocket);
session.OnConnected(args.AcceptSocket.RemoteEndPoint);
개선점:
- 유연성 증가:
Func<Session>을 사용하여 세션 객체의 생성 방식을 외부에서 결정할 수 있다. - 책임 분리:
Listener클래스는 세션 생성과 초기화에 대한 책임을 외부로 위임하여 역할이 단순화되었다.
2) Program 클래스
변경 전:
Program 클래스에서 직접 소켓 처리를 담당.
static void Main(string[] args)
{
Listener listener = new Listener();
listener.Init(endPoint, OnAcceptHandler);
}
변경 후:
Session을 상속받는 GameSession 클래스를 정의하여, 프로그램이 특정 세션 로직을 처리할 수 있도록 개선되었다.
class GameSession : Session
{
public override void OnConnected(EndPoint endPoint)
{
Console.WriteLine($"Client connected: {endPoint}");
}
}
static void Main(string[] args)
{
Listener listener = new Listener();
listener.Init(endPoint, () => new GameSession());
}
개선점:
- 확장성 강화:
Session을 상속받아 다양한 세션 동작을 정의할 수 있다. - 캡슐화 강화: 세션 처리 로직이
Program에서 분리되어 더 명확해졌다.
3) Session 클래스
추가된 기능:
OnConnected메서드: 클라이언트가 연결되었을 때의 동작을 정의하는 메서드가 추가되었다.
public virtual void OnConnected(EndPoint endPoint)
{
Console.WriteLine($"Connected to: {endPoint}");
}
OnRecv메서드: 데이터를 수신했을 때의 동작을 정의하는 메서드가 추가되었다.
public virtual void OnRecv(ArraySegment<byte> buffer)
{
string receivedData = Encoding.UTF8.GetString(buffer.Array, buffer.Offset, buffer.Count);
Console.WriteLine($"Received: {receivedData}");
}
OnSend메서드: 데이터를 송신했을 때 호출되는 메서드가 추가되었다.
public virtual void OnSend(int numOfBytes)
{
Console.WriteLine($"Sent {numOfBytes} bytes.");
}
OnDisconnected메서드: 클라이언트와의 연결이 종료되었을 때 호출되는 메서드가 추가되었다.
public virtual void OnDisconnected(EndPoint endPoint)
{
Console.WriteLine($"Disconnected from: {endPoint}");
}
추가된 기능:
OnConnected메서드: 클라이언트가 연결되었을 때의 동작을 정의하는 메서드가 추가되었다.
public virtual void OnConnected(EndPoint endPoint)
{
Console.WriteLine($"Connected to: {endPoint}");
}
개선점:
- 커스터마이징 가능:
Session클래스를 상속받아 각기 다른 연결 동작을 정의할 수 있다. - 책임 분리: 연결 이벤트 처리가 개별 세션으로 위임되어 유지보수가 용이해졌다.
3. 개선 효과
- 코드 가독성 향상:
Listener와Session의 역할이 명확히 분리되어 각 클래스의 책임이 분명해졌다. - 확장성 증가: 세션 생성 방식을 외부로 위임하여 새로운 세션 동작을 쉽게 추가할 수 있다.
- 재사용성 강화:
Session클래스를 상속받아 다양한 로직을 캡슐화할 수 있다.
4. 마무리
서버 엔진(ServerCore 프로젝트)에서 다뤄야 하는 네트워크 통신 관련 코드들과 서버(Server 프로젝트)에서 다루게 될 게임 컨텐츠 관련 코드를 구분해야, 유지보수와 협업이 쉽다.