Project History/원격 제어 프로그램 만들기

[C# 원격 제어 프로그램 만들기 #01] 서버 - 클라이언트 통신 구조 만들기

JeongKyun 2021. 12. 26.
반응형

서론

이 글에서 다른 PC에 접속하기 위해서 가장 중요한 TCP/IP 통신을 이용한 서버와 클라이언트의 비동기 소켓 구조로 만든 소스를 정리 할려고한다. 통신간 기능 로직은 아직 작성하지 않았고 Connect - Accept 과정을 작성한 글이며, 자세한 기능 로직은 추 후 완성 코드를 보면 좋을 것 같다. 개비할수록 소스의 변형이 일어날 수 있지만 처음 설계는 멀티스레드 구조가 아닌 비동기로 작성했다.

(쓰레드를 안돌리고 비동기로 작성한 이유는 정리하여 이 후에 작성해보겠다.)

 

코드 (클라이언트)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace 원격제어_프로그램
{
    public static class SetupClient
    {
        public static event EventHandler ConnectedEventHandler = null;
        public static event EventHandler ConnectFiledEventHandler = null;

        static Socket sock = null;

        public static void Setup(string ip, int port)
        {
            IPAddress ipaddr = IPAddress.Parse(ip);
            IPEndPoint ep = new IPEndPoint(ipaddr, port);

            sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            //비동기 Connect
            sock.BeginConnect(ep, DoConnect, null);
        }

        /// <summary>
        /// 비동기 Connect 함수
        /// </summary>
        /// <param name="result"></param>
        static void DoConnect(IAsyncResult result)
        {
            IAsyncResult ar = result;

            try
            {
                sock.EndConnect(result);
                //비동기니까 값이 없을 수도 있으니 이벤트 핸들러 null 체크
                if(ConnectedEventHandler != null)
                {
                    ConnectedEventHandler(null, new EventArgs());
                }
            }
            catch (SocketException sock_ex)
            {
                if(ConnectFiledEventHandler != null)
                {
                    ConnectFiledEventHandler(null, new EventArgs());
                }
            }
            sock.Close();
        }

    }
}

 

코드 (서버)

using MyDemoLib;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace 원격제어_프로그램
{
    class SetupServer
    {
        static Socket lis_sock;
        public static event RecvRCInfoEventHandler RecvedRCInfoEventHandler = null;
        static string ip = string.Empty;
        static int port = -1;

        public static void Start(string ip, int port)
        {
            SetupServer.ip = ip;
            SetupServer.port = port;
            SocketBooting();

        }

        private static void SocketBooting()
        {
            IPAddress ipaddr = IPAddress.Parse(ip);
            IPEndPoint ep = new IPEndPoint(ipaddr, port);
            lis_sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            lis_sock.Bind(ep);
            lis_sock.Listen(1);
            lis_sock.BeginAccept(DoAccept, null);
        }

        private static void DoAccept(IAsyncResult result)
        {
            if (lis_sock == null)
                return;

            try
            {
                Socket sock = lis_sock.EndAccept(result);
                DoIt(sock);
                lis_sock.BeginAccept(DoAccept, null);

            }
            catch (Exception ex)
            {
                Close();
            }
        }

        private static void DoIt(Socket dosock)
        {
            if(RecvedRCInfoEventHandler != null)
            {
                RecvRCInfoEventArgs e = new RecvRCInfoEventArgs(dosock.RemoteEndPoint);
                RecvedRCInfoEventHandler(null, e);
            }
            dosock.Close();
        }

        public static void Close()
        {
            if(lis_sock != null)
            {
                lis_sock.Close();
                lis_sock = null;
            }
        }
    }
}

 

현재 기본 통신 껍데기만 만들어져있는 상태이며 상세 로직은 추 후 추가 예정이다.

 

Server는 Mainform Load시 Start함수로 비동기 방식으로 Listen 대기 예정.

Client는 비동기 함수인 BeginAccept를 이용하여 서버에게 Connect함.

댓글

💲 많이 본 글