(C# : Server) Connector

Posted by : at

Category : Charp-Server



// DummyClient
// Program.cs

namespace DummyClient
{
    class Program
    {
        static void Main(string[] args)
        {
            string host = Dns.GetHostName();
            IPHostEntry ipHost = Dns.GetHostEntry(host);
            IPAddress ipAddr = ipHost.AddressList[0];
            IPEndPoint endPoint = new IPEndPoint(ipAddr, 7777/* Port */);

            Socket socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

            try
            {
                // Connect는 무한 대기하기에 여기를 Connector로 만들어 비동기화 해보자
                socket.Connect(endPoint);
                Console.WriteLine($"Connected To {socket.RemoteEndPoint.ToString()}...");

// ...

ServerCore에 Connector 클래스 생성

// ServerCore
// Connector.cs

namespace ServerCore
{
    class Connector
    {
        public void Connect(IPEndPoint endPoint)
        {
            Socket socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

            SocketAsyncEventArgs args = new SocketAsyncEventArgs();
            args.Completed += OnConnectComplete;
            args.RemoteEndPoint = endPoint;

            // UserToken를 이용해서 원하는 데이터를 넘길 수 있음
            args.UserToken = socket;

            RegisterConnect(args);
        }

        void RegisterConnect(SocketAsyncEventArgs args)
        {
            Socket socket = args.UserToken as Socket;
            if (socket == null)
                return;

            bool pending = socket.ConnectAsync(args);
            if (pending == false)
                OnConnectComplete(null, args);
        }

        void OnConnectComplete(object sender, SocketAsyncEventArgs args)
        {
            if(args.SocketError == SocketError.Success)
            {
                // Connect후 동작을 정의해야함
                // Session을 받아서 처리하게 할 예정(아래 참고)
            }
            else
            {
                Console.WriteLine($"OnConnect Completed Fail : {args.SocketError}");
            }
        }
    }
}

class Connector
{
    // sessionFactory를 통해서 생성된 session을 전달 받을 예정
    Func<Session> _sessionFactory;

    public void Connect(IPEndPoint endPoint, Func<Session> sessionFactory)
    {
        Socket socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

        SocketAsyncEventArgs args = new SocketAsyncEventArgs();
        args.Completed += OnConnectComplete;
        args.RemoteEndPoint = endPoint;

        _sessionFactory += sessionFactory;

// ...

void OnConnectComplete(object sender, SocketAsyncEventArgs args)
{
    if(args.SocketError == SocketError.Success)
    {
        Session session = _sessionFactory.Invoke();
        session.Start(args.ConnectSocket);
        session.OnConnected(args.RemoteEndPoint);
    }
    
    //...

이제 DummyClient에서 ServerCore의 Connect 클래스를 사용하면 되는데
그냥 using을 써서 사용이 안된다.
아래처럼 사용하자

  • ServerCore 우클릭 -> 속성
  • 출력 형식 -> 클래스 라이브러리로 변경

  • Server, DummyClient 우클릭 -> 추가 -> 참조
  • ServerCore 클릭 후 확인

여기까지하면 ServerCore를 외부에서 사용이 가능

// DummyClient
// Program.cs

namespace DummyClient
{
    class GameSession : Session
    {
        public override void OnConnected(EndPoint endPoint)
        {
            Console.WriteLine($"[OnConnected] {endPoint}");

            // 보내는 부분
            byte[] sendBuff = Encoding.UTF8.GetBytes("Hello World!");
            Send(sendBuff);
        }

        public override void OnRecv(ArraySegment<byte> buffer)
        {
            string recvData = Encoding.UTF8.GetString(buffer.Array, buffer.Offset, buffer.Count);
            Console.WriteLine($"[From Server] {recvData}");
        }

        public override void OnSend(int numOfBytes)
        {
            Console.WriteLine($"[OnSend] {numOfBytes}");
        }

        public override void OnDisconnected(EndPoint endPoint)
        {
            Console.WriteLine($"[OnDisconnected] {endPoint}");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            string host = Dns.GetHostName();
            IPHostEntry ipHost = Dns.GetHostEntry(host);
            IPAddress ipAddr = ipHost.AddressList[0];
            IPEndPoint endPoint = new IPEndPoint(ipAddr, 7777/* Port */);

            Connector connector = new Connector();
            connector.Connect(endPoint, () => { return new GameSession(); });

About Taehyung Kim

안녕하세요? 8년차 현업 C++ 개발자 김태형이라고 합니다. 😁 C/C++을 사랑하며 다양한 사람과의 협업을 즐깁니다. ☕ 꾸준한 자기개발을 미덕이라 생각하며 노력중이며, 제가 얻은 지식을 홈페이지에 정리 중입니다. 좀 더 상세한 제 이력서 혹은 Private 프로젝트 접근 권한을 원하신다면 메일주세요. 😎

Star
Useful Links