원격 제어 프로그램 4. 원격 제어 요청 클라이언트

*동영상 강의에서는 Connect 부분을 비동기로 처리하는 BeginConnect를 호출합니다. 그리고 연결 요청 성공과 실패를 처리할 수 있게 이벤트를 추가 정의하였습니다. *

원격 제어를 요청하는 SetupClient 클래스를 구현합시다.

SetupClient는 단순히 상대에게 누가 요청하는지 알려주는 역할만 수행할 거예요. 값을 유지할 필요도 없고 개체를 만들 필요도 없는 클래스이므로 정적 클래스로 정의하세요.

public static class SetupClient
{

Setup 클라이언트에서는 원격 제어하고자 하는 상대 IP와 포트 정보를 입력 인자로 받습니다.

    public static void Setup(string ip, int port)
    {

상대 IP 주소를 입력 인자로 IPEndPoint 개체를 생성하세요.

        IPAddress ipaddr = IPAddress.Parse(ip); //상대 IP 주소 개체를 생성
        IPEndPoint ep = new IPEndPoint(ipaddr, port); //IP 단말 주소(IP주소 + 포트번호) 개체 생성

TCP 방식의 소켓을 생성합니다.

        //TCP 소켓 생성(네트워크 주소 체계, 전송 방식, 프로토콜)
        Socket sock = new Socket(AddressFamily.InterNetwork, //네트워크 주소 체계
            SocketType.Stream, //전송 방식
            ProtocolType.Tcp);//프로토콜

연결한 후에 바로 닫습니다. 원격 제어를 수용할 지 여부를 판단하는 곳에 원격 제어 요청이 있다는 것을 알려주는 목적 뿐이어서 전달할 정보는 없습니다.

        sock.Connect(ep);//연결 요청
        sock.Close();//소켓 닫기
    }
}

이처럼 작성하여 컴파일하면 “형식 또는 네임 스페이스 이름을 찾을 수 없습니다.”와 같은 오류 메시지가 뜰 거예요. IPAddress와 IPEndPoint, Socket 등을 사용하기 위해 필요한 네임 스페이스를 소스 코드 맨 위에 추가하세요.

using System.Net;
using System.Net.Sockets;

Microsoft Visual Studio에서 프로그래밍할 때 어떠한 형식이 어느 namespace에 있는지 모르더라도 작성한 형식 이름에 커서를 위치한 상태에서 Ctrl키와 .(DOT)을 누르면 아래처럼 인텔리센스가 동작하여 쉽게 using 문을 추가할 수 있습니다. (개발 도구 버전에 따라 다를 수 있습니다.)

[그림 8] 인텔리센스 기능으로 using 문 추가
[그림 8] 인텔리센스 기능으로 using 문 추가

다음은 이번 실습에서 작성한 소스 코드입니다.

//SetupClient.cs
using System.Net;
using System.Net.Sockets;

namespace 원격제어기
{
    /// <summary>
    /// 원격 제어 요청 클라이언트 - 정적 클래스
    /// </summary>
    public static class SetupClient
    {
        /// <summary>
        /// 원격 제어 요청 메서드
        /// </summary>
        /// <param name="ip">상대 IP 주소</param>
        /// <param name="port">상대 포트 번호</param>
        public static void Setup(string ip, int port)
        {
            IPAddress ipaddr = IPAddress.Parse(ip); //상대 IP 주소 개체를 생성
            IPEndPoint ep = new IPEndPoint(ipaddr, port); //IP 단말 주소(IP주소 + 포트번호) 개체 생성
            //TCP 소켓 생성(네트워크 주소 체계, 전송 방식, 프로토콜)
            Socket sock = new Socket(AddressFamily.InterNetwork, //네트워크 주소 체계
                SocketType.Stream, //전송 방식
                ProtocolType.Tcp);//프로토콜
            sock.Connect(ep);//연결 요청
            sock.Close();//소켓 닫기
        }
    }
}

 다음은 연결 요청 부분을 비동기로 처리하여 연결 요청 과정에 Blocking 현상이 발생하지 않도록 품질 수준을 높인 코드입니다.  동영상 강의를 참고하세요.

using System;
using System.Net;
using System.Net.Sockets;

namespace 원격제어기
{
    ///
    /// 원격 제어 요청 클라이언트 - 정적 클래스
    /// 
    public static class SetupClient
    {
        public static event EventHandler ConnectedEventHandler = null;
        public static event EventHandler ConnectFailedEventHandler = null;
        static Socket sock;
        ///
        /// 원격 제어 요청 메서드
        /// 
        ///상대 IP 주소
        ///상대 포트 번호
        public static void Setup(string ip, int port)
        {
            IPAddress ipaddr = IPAddress.Parse(ip); //상대 IP 주소 개체를 생성
            IPEndPoint ep = new IPEndPoint(ipaddr, port); //IP 단말 주소(IP주소 + 포트번호) 개체 생성
            //TCP 소켓 생성(네트워크 주소 체계, 전송 방식, 프로토콜)
            sock = new Socket(AddressFamily.InterNetwork, //네트워크 주소 체계
                SocketType.Stream, //전송 방식
                ProtocolType.Tcp);//프로토콜
            //sock.Connect(ip, port);
            sock.BeginConnect(ep, DoConnect, sock);
        }
        static void DoConnect(IAsyncResult result)
        {            
            try
            {
                sock.EndConnect(result);
                if(ConnectedEventHandler != null)
                {
                    ConnectedEventHandler(null, new EventArgs());//연결 성공
                }
            }
            catch
            {
                if(ConnectFailedEventHandler != null)
                {
                    ConnectFailedEventHandler(null, new EventArgs());//연결 실패
                }
            }
            sock.Close();
        }
    }
}