첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
유용한 소스 코드가 있으면 icodebroker@naver.com으로 보내주시면 감사합니다.
블로그 자료는 자유롭게 사용하세요.

■ Ping 관리자

------------------------------------------------------------------------------------------------------------------------

using System;

using System.Net;

using System.Net.Sockets;

using System.Threading;

 

/// <summary>

/// Ping 관리자

/// </summary>

public class PingManager

{

    //////////////////////////////////////////////////////////////////////////////////////////////////// Field

    ////////////////////////////////////////////////////////////////////////////////////////// Protected

 

    #region Field

 

    /// <summary>

    /// 소켓

    /// </summary>

    protected Socket socket;

 

    /// <summary>

    /// 열기 여부

    /// </summary>

    protected bool isOpen;

 

    /// <summary>

    /// 수동 리셋 이벤트

    /// </summary>

    /// <remarks>읽기 완료 여부용</remarks>

    protected ManualResetEvent manualResetEvent;

 

    /// <summary>

    /// 최근 시퀀스

    /// </summary>

    protected byte lastSequence = 0;

 

    /// <summary>

    /// Ping 명령

    /// </summary>

    protected byte[] pingCommandByteArray;

 

    /// <summary>

    /// Ping 결과

    /// </summary>

    protected byte[] pingResultByteArray;

 

    #endregion

 

    //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor

    ////////////////////////////////////////////////////////////////////////////////////////// Public

 

    #region 생성자 - PingManager()

 

    /// <summary>

    /// 생성자

    /// </summary>

    public PingManager()

    {

        this.pingCommandByteArray = new byte[8];

 

        this.pingCommandByteArray[0] = 8; // Type

        this.pingCommandByteArray[1] = 0; // Subtype

        this.pingCommandByteArray[2] = 0; // Checksum

        this.pingCommandByteArray[3] = 0;    

        this.pingCommandByteArray[4] = 1; // Identifier

        this.pingCommandByteArray[5] = 0;

        this.pingCommandByteArray[6] = 0; // Sequence number

        this.pingCommandByteArray[7] = 0;

 

        // returned IP Header + optional data

        this.pingResultByteArray = new byte[this.pingCommandByteArray.Length + 1000];

    }

 

    #endregion

 

    //////////////////////////////////////////////////////////////////////////////////////////////////// Method

    ////////////////////////////////////////////////////////////////////////////////////////// Public

 

    #region 열기 - Open()

 

    /// <summary>

    /// 열기

    /// </summary>

    public void Open()

    {

        this.socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp);

 

        this.isOpen = true;

 

        this.manualResetEvent = new ManualResetEvent(false);

    }

 

    #endregion

 

    #region 전송하기 - Send(ipAddress, timeOut)

 

    /// <summary>

    /// 전송하기

    /// </summary>

    /// <param name="ipAddress">IP 주소</param>

    /// <param name="timeOut">타임아웃</param>

    /// <returns>경과 시간</returns>

    public TimeSpan Send(string ipAddress, TimeSpan timeOut)

    {

        while(this.socket.Available > 0)

        {

            this.socket.Receive

            (

                this.pingResultByteArray,

                Math.Min(this.socket.Available, this.pingResultByteArray.Length),

                SocketFlags.None

            );

        }

 

        this.manualResetEvent.Reset();

 

        DateTime sendDateTime = DateTime.Now;

 

        this.pingCommandByteArray[6] = this.lastSequence++; // complete ping command

 

        SetChecksum(this.pingCommandByteArray);

            

        int countSent = this.socket.SendTo(this.pingCommandByteArray, new IPEndPoint(IPAddress.Parse(ipAddress), 0));

 

        this.socket.BeginReceive

        (

            this.pingResultByteArray,

            0,

            this.pingResultByteArray.Length,

            SocketFlags.None,

            new AsyncCallback(Socket_EndReceive),

            null

        );

 

        if(this.manualResetEvent.WaitOne(timeOut, false)) // 데이터를 수신할 때까지 대기한다.

        {

            if

            (

                (this.pingResultByteArray[20] == 0                           ) &&

                (this.pingCommandByteArray[4] == this.pingResultByteArray[24]) &&

                (this.pingCommandByteArray[5] == this.pingResultByteArray[25]) &&

                (this.pingCommandByteArray[6] == this.pingResultByteArray[26]) &&

                (this.pingCommandByteArray[7] == this.pingResultByteArray[27])

            )

            {

                return DateTime.Now.Subtract(sendDateTime); // 경과 시간 반환

            }

        }

 

        return TimeSpan.MaxValue;

    }

 

    #endregion

 

    #region 닫기 - Close()

 

    /// <summary>

    /// 닫기

    /// </summary>

    public void Close()

    {

        this.isOpen = false;

 

        this.socket.Close();

 

        this.manualResetEvent.Close();

    }

 

    #endregion

 

    ////////////////////////////////////////////////////////////////////////////////////////// Protected

 

    #region 체크썸 설정하기 - SetChecksum(sourceByteArray)

 

    /// <summary>

    /// 체크썸 설정하기

    /// </summary>

    /// <param name="sourceByteArray">소스 바이트 배열</param>

    protected void SetChecksum(byte[] sourceByteArray)

    {

        sourceByteArray[2] = 0;

        sourceByteArray[3] = 0;

 

        uint checksum = 0;

 

        for(int i = 0; i < this.pingCommandByteArray.Length; i = i + 2)

        {

            checksum += BitConverter.ToUInt16(this.pingCommandByteArray, i);

        }

 

        checksum = ~((checksum & 0xffffu) + (checksum >> 16));

 

        sourceByteArray[2] = (byte)checksum;

        sourceByteArray[3] = (byte)(checksum >> 8);

    }

 

    #endregion

 

    #region 소켓 수신 완료시 처리하기 - Socket_EndReceive(asyncResult)

 

    /// <summary>

    /// 소켓 수신 완료시 처리하기

    /// </summary>

    /// <param name="asyncResult">비동기 결과</param>

    protected void Socket_EndReceive(IAsyncResult asyncResult)

    {

        if(this.isOpen)

        {

            try

            {

                this.socket.EndReceive(asyncResult);

            }

            catch(Exception)

            {

            }

 

            this.manualResetEvent.Set();

        }

    }

 

    #endregion

}

------------------------------------------------------------------------------------------------------------------------

Posted by 사용자 icodebroker

댓글을 달아 주세요