(C# : Server) Session - 1

Posted by : at

Category : Charp-Server



// ServerCore
// Main.cs

class Program
{
    static Listner _listener = new Listner();

    static void OnAcceptHandler(Socket clientSocket)
    {
        try
        {
            /*
                Main에서 데이터를 받는 부분을 Session으로 빼보자
            */

            // 받는 부분
            byte[] recvBuff = new byte[1024];
            int recvBytes = clientSocket.Receive(recvBuff);
            string recvData = Encoding.UTF8.GetString(recvBuff, 0/*시작인덱스*/, recvBytes/*문자열이 몇개인가*/);

            Console.WriteLine($"[From Client] {recvData}");

            // 보내는 부분
            byte[] sendBuff = Encoding.UTF8.GetBytes("Welcom to MMORPG Server ");
            clientSocket.Send(sendBuff);

            // 소켓을 닫는다
            clientSocket.Shutdown(SocketShutdown.Both); /*소켓을 닫는다를 미리 공지*/
            clientSocket.Close();   /*실제로 닫는 부분*/
        }
        catch(Exception e)
        {

        }
    }

    static void Main(string[] args)
    {
        // DNS(Domain Name System)을 사용할 예정
        // ip addr를 안쓰고 도메인네임을 쓰겠다는 말.
        string host = Dns.GetHostName();
        IPHostEntry ipHost = Dns.GetHostEntry(host);
        IPAddress ipAddr = ipHost.AddressList[0];
        IPEndPoint endPoint = new IPEndPoint(ipAddr, 7777/* Port */);

        _listener.Init(endPoint, OnAcceptHandler);

        while(true)
        {
        }
    }
}
// ServerCore
// Session.cs

class Session
{
    Socket _socket;

    public void Start(Socket socket)
    {
        _socket = socket;
        SocketAsyncEventArgs recvArgs = new SocketAsyncEventArgs();
        recvArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnRecvComplete);
        recvArgs.SetBuffer(new byte[1024], 0/*시작인덱스*/, 1024);

        RegisterRecv(recvArgs);
    }

    public void Send(byte[] sendBuff)
    {
        _socket.Send(sendBuff);
    }

    public void Disconnect()
    {
        _socket.Shutdown(SocketShutdown.Both);
        _socket.Close();
    }

    void RegisterRecv(SocketAsyncEventArgs args)
    {
        bool pending = _socket.ReceiveAsync(args);
        if(pending == false)
            OnRecvComplete(null, args);
    }

    void OnRecvComplete(object sender, SocketAsyncEventArgs args)
    {
        if(args.BytesTransferred > 0 && args.SocketError ==SocketError.Success)
        {
            try{
                string recvData = Encoding.UTF8.GetString(args.Buffer, args.Offset, args.BytesTransferred);
                RegisterRecv(args);
            }
            catch()
            {

            }
        }
        else
        {
            // Disconnect
        }
    }
}
// ServerCore
// Main.cs

class Program
{
    static Listner _listener = new Listner();

    static void OnAcceptHandler(Socket clientSocket)
    {
        try
        {
            Session session = new Session();
            session.Start(clientSocket);

            byte[] sendBuff = Encoding.UTF8.GetBytes("Welcom to MMORPG Server ");
            session.Send(sendBuff);

            Thread.Sleep(1000);

            session.Disconnect();
        }
        catch(Exception e)
        {

        }
    }

    static void Main(string[] args)
    {
        // DNS(Domain Name System)을 사용할 예정
        // ip addr를 안쓰고 도메인네임을 쓰겠다는 말.
        string host = Dns.GetHostName();
        IPHostEntry ipHost = Dns.GetHostEntry(host);
        IPAddress ipAddr = ipHost.AddressList[0];
        IPEndPoint endPoint = new IPEndPoint(ipAddr, 7777/* Port */);

        _listener.Init(endPoint, OnAcceptHandler);

        while(true)
        {
        }
    }
}

한 가지 안전하지 못한 부분이 있다

public void Disconnect()
{
    /*
    멀티쓰레드 환경에서
    Disconnect가 두 번 발생할 경우 에러가 발생
    */
    _socket.Shutdown(SocketShutdown.Both);
    _socket.Close();
}
// ServerCore
// Session.cs

class Session
{
    Socket _socket;
    int _disconnected = 0;

    // ...

    public void Disconnect()
    {
        if(Interlocked.Exchange(ref _disconnected, 1) == 1)
            return;
        
        _socket.Shutdown(SocketShutdown.Both);
        _socket.Close();
    }

About Taehyung Kim

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

Star
Useful Links