Session Send코드 알아보러가기
네트워크 프로그래밍 -Send코드 개선하기
Send 코드 참조 네트워크 프로그래밍 - C# Non - blocking을 사용한 Server 소켓프로그래밍의 Send Receive코드 알아보러 가기 네트워크 프로그래밍 - C# Non - blocking을 사용한 Server 소켓프로그래밍의 Receive Li
code-piggy.tistory.com
엔진과 컨텐츠 분리하기
이벤트 핸들러는 엔진에서 발생하는 이벤트를 처리하고 이벤트가 발생할 때 컨텐츠에 알림을 전달한다.
아래 메서드들을 통해 이벤트 핸들러와 연동될 수 있다.
public void OnConnected(EndPoint endPoint) {}
public void OnReceive(ArraySegment<byte> buffer){}
public void OnSend(int numofBytes){}
public void OnDisconnected(EndPoint endPoint) { }
01 OnConnected
클라이언트 접속을 알리는 시점이다. endPoint는 연결된 주소를 나타낸다.
02 OnReceive
데이터가 수신된 경우 호출된다. buffer는 수신한 데이터를 담고 있다.
03 OnSend
데이터를 전송한 후 호출된다. numofBytes는 전송된 데이터의 바이트 수를 나타낸다.
04 OnDisconnected
네트워크가 종료되었을때 호출된다. endPoint는 연결이 종료된 주소를 나타낸다.
Event 받아주는 방식
1. EventHandler를 만들어서 연결
class Sessionhandler
{
public void OnConnected(EndPoint endPoint) { }
public void OnReceive(ArraySegment<byte> buffer) { }
public void OnSend(int numofBytes) { }
public void OnDisconnected(EndPoint endPoint) { }
}
2. Session을 상속 받아서 만드는 방법
Session.cs
public abstract void OnConnected(EndPoint endPoint);
public abstract void OnReceive(ArraySegment<byte> buffer);
public abstract void OnSend(int numofBytes);
public abstract void OnDisconnected(EndPoint endPoint);
각 메서드들은 해당 이벤트에 대한 사용자가 정의한 동작을 구현한다.
Program.cs
class GameSeesion : Session
{
public override void OnConnected(EndPoint endPoint)
{
}
public override void OnDisconnected(EndPoint endPoint)
{
}
public override void OnReceive(ArraySegment<byte> buffer)
{
}
public override void OnSend(int numofBytes)
{
}
}
01 GameSession클래스를 이용해서 인스턴스화하여 사용
이제는 Session을 바로 만들 수 없고 상속 받은 GameSession을 이용해야 한다.
그 이유는 Session클래스가 추상클래스가 되었고 추상 클래스는 직접 인스턴스화를 할 수 없기 때문이다.
변경 전
static void onAcceptHandler(Socket clientSocket)
{
try
{
Session session = new Session();
}
}
변경 후
static void onAcceptHandler(Socket clientSocket)
{
try
{
GameSession session = new GameSession();
}
}
연동하는 방법
01 OnDisconnected
컨텐츠에 연결이 종료되었음을 알리는 역할
Session.cs
public void Disconnect()
{
if (Interlocked.Exchange(ref _disconnected, 1) == 1)
return;
OnDisconnected(_socket.RemoteEndPoint);
_socket.Shutdown(SocketShutdown.Both);
_socket.Close();
}
02 OnReceive
컨텐츠에 데이터가 수신되었음을 알리는 역할
Session.cs
void OnRecvCompleted(object sender, SocketAsyncEventArgs args)
{
if(args.BytesTransferred > 0 && args.SocketError == SocketError.Success)
{
try
{
OnReceive(new ArraySegment<byte>(args.Buffer, args.Offset, args.BytesTransferred));
RegisterRecv();
}
... 생략
}
args.Buffer - 수신된 데이터가 저장된 바이트 배열
args.Offset - 배열의 시작위치
args.ByteTrasnferred - 수신된 바이트의 수
원래 있던 부분은 컨텐츠 쪽으로 이동한다.
public override void OnReceive(ArraySegment<byte> buffer)
{
string recvData = Encoding.UTF8.GetString(buffer.Array, buffer.Offset, buffer.Count);
Console.WriteLine($"[From Client] {recvData}");
}
03 OnSend
컨텐츠에 데이터가 전송 되었음을 알리는 역할
void OnSendCompleted(object sender, SocketAsyncEventArgs args)
{
lock (_lock)
{
if (args.BytesTransferred > 0 && args.SocketError == SocketError.Success)
{
try
{
_sendArgs.BufferList = null;
_pendlingList.Clear();
OnSend(_sendArgs.BytesTransferred);
... 생략
원래 있던 부분은 컨텐츠 쪽으로 이동한다.
public override void OnSend(int numofBytes)
{
Console.WriteLine($"Transfoerred bytes : {numofBytes}");
}
OnAcceptHandler & OnAcceptCompleted 보수 작업하기
01 OnAcceptHandler
원래 OnAcceptHandler 에서 클라이언트 소켓을 매개변수로 받아와서 해당 클라이언트와 통신을 처리하는 GameSession을 생성하고 시작하게 하였다.
Program.cs
static void onAcceptHandler(Socket clientSocket)
{
try
{
GameSession session = new GameSession();
session.Start(clientSocket);
... 생략
02 OnAcceptCompleted
비동기로 클라이언트가 서버에 접속하고자 할 때 서버가 클라이언트의 연결 요청을 수락하였을때 호출되며 args.AcceptSocket을 통해 연결된 클라이언트의 소켓을 전달 받았다.
Listener.cs
void OnAcceptCompleted(object sender, SocketAsyncEventArgs args)
{
if(args.SocketError == SocketError.Success)
{
_onAcceptHandler.Invoke(args.AcceptSocket);
}
... 생략
이벤트 핸들러 내에서 GameSession을 생성하고 시작하는 코드를 작성하는 것이 더 좋다. 왜냐하면 위의 설명과 같이 접속 요청과 연결 요청이 완료되었을때 GameSession을 생성하고 클라이언트와의 통신을 처리해야하기 때문이다.
void OnAcceptCompleted(object sender, SocketAsyncEventArgs args)
{
if(args.SocketError == SocketError.Success)
{
GameSession session = new GameSession();
session.Start(args.AcceptSocket);
_onAcceptHandler.Invoke(args.AcceptSocket);
}
... 생략
외부에서 Session객체 만들기
원래 안에서 Session객체를 만들었었는데 이 부분을 외부에서 만들도록 할 것이다.
void OnAcceptCompleted(object sender, SocketAsyncEventArgs args)
{
if(args.SocketError == SocketError.Success)
{
GameSession session = new GameSession();
session.Start(args.AcceptSocket);
Session.OnConnected(args.AcceptSocket.RemoteEndPoint);
}
... 생략
외부에서 객체를 만들게 되면 다양한 장점을 가지게 되며 생성 방식을 제어할 수 있고 변경 가능하게 하며 객체를 여러 곳에서 재사용할 수 있게 한다.
// 매개 변수가 없고 Session타입의 객체를 반환하는 델리게이트 형식이다.
Func<Session> _sessionFactory;
public void Init(IPEndPoint endPoint,Func<Session> sessionFactory)
{
_sessionFactory += sessionFactory;
}
void OnAcceptCompleted(object sender, SocketAsyncEventArgs args)
{
if(args.SocketError == SocketError.Success)
{
Session session = _sessionFactory.Invoke();
session.Start(args.AcceptSocket);
session.OnConnected(args.AcceptSocket.RemoteEndPoint);
}
... 생략
_listener.Init(endPoint,()=> { return new GameSession(); });
()=> { return new GameSession(); } 이 부분을 통해 람다식을 사용하여 팩토리 메서드를 정의 한 것을 확인할 수 있다.
매개변수가 없고 GameSession객체를 반환하는 메서드이다.
최종 코드
public override void OnConnected(EndPoint endPoint)
{
Console.WriteLine($"OnConnected : {endPoint}");
byte[] sendBuff = Encoding.UTF8.GetBytes("Welcome to piggy Server");
Send(sendBuff);
Thread.Sleep(1000);
Disconnect();
}
public override void OnDisconnected(EndPoint endPoint)
{
Console.WriteLine($"OnDisconnected : {endPoint}");
}
public override void OnReceive(ArraySegment<byte> buffer)
{
string recvData = Encoding.UTF8.GetString(buffer.Array, buffer.Offset, buffer.Count);
Console.WriteLine($"[From Client] {recvData}");
}
public override void OnSend(int numofBytes)
{
Console.WriteLine($"Transfoerred bytes : {numofBytes}");
}
참고 : 본 내용은 MMORPG PART4 강의를 수강하여 작성하였습니다.
https://www.inflearn.com/course/%EC%9C%A0%EB%8B%88%ED%8B%B0-mmorpg-%EA%B0%9C%EB%B0%9C-part4
'cs공부 > 네트워크프로그래밍' 카테고리의 다른 글
네트워크프로그래밍 - Session이란 (0) | 2023.07.15 |
---|---|
네트워크프로그래밍 - C# Non - blocking을 사용한 Server 소켓프로그래밍의 Connector (0) | 2023.07.15 |
네트워크 프로그래밍 -Send코드 개선하기 (0) | 2023.07.13 |
네트워크 프로그래밍 - C# Non - blocking을 사용한 Server 소켓프로그래밍의 Send (0) | 2023.07.07 |
네트워크 프로그래밍 - C# Non - blocking을 사용한 Server 소켓프로그래밍의 Receive (0) | 2023.07.03 |
댓글