프로젝트

[핑 체크하는 프로그램 만들기 - 1] 핑 체크 후 결과 시각화 하는 코드

lko9911_ 2025. 11. 28. 10:55

 

핑 체크하는 프로그램 만들기 - 개요

 

네트워크 연결성은 현대 정보화 시대의 핵심 요소로, 다양한 디지털 서비스와 장비는 안정적인 통신 환경을 기반으로 운영됩니다. 특히 연구실, 기업, 산업 현장에서는 서버와 장비 간의 연결 상태를 실시간으로 모니터링하고, 장애 발생 시 즉각적인 대응이 이루어져야 시스템 전체의 안정성이 보장됩니다. 그러나 기존 네트워크 모니터링 솔루션은 복잡한 구성이나 고비용의 상용 소프트웨어에 의존하는 경우가 많아, 단순한 연결 상태 점검을 필요로 하는 사용자에게는 과도한 부담이 될 수 있습니다.

 

핑(Ping)은 이러한 네트워크 연결 상태를 확인하는 데 가장 기본적이면서도 효과적인 도구로, 대상 장비와의 지연 시간, 패킷 손실 여부 등을 직관적으로 파악할 수 있습니다. 하지만 일반적인 핑 명령어는 단순한 단발성 테스트나 콘솔 기반 확인에 한정되어 있어, 실시간 모니터링·상태 기록·시각화 등 고급 기능이 필요한 경우에는 한계가 존재합니다.

 

이에 본 프로젝트에서는 여러 장비의 네트워크 상태를 자동으로 측정하고, 결과를 시각적으로 제공하며, 임계값 초과 시 알림 기능까지 포함한 ‘핑 체크 프로그램’을 개발하는 것을 목표로 하였습니다. 또한 간단하고 가벼운 구조를 유지하면서도, 다양한 환경에서 활용할 수 있도록 확장성과 편의성을 고려하여 프로그램을 설계했습니다.

 

프로젝트의 목표

 

1. 로컬 디바이스의 실제 IP 주소 자동 탐지 기능 구현

  • Docker·WSL·가상환경 등이 아닌 실제 로컬 네트워크 인터페이스의 IP를 반환하도록 설계하였습니다.
  • socket 모듈을 활용해 외부 연결을 시도함으로써, 시스템이 사용하는 진짜 로컬 IP를 정확하게 선택합니다.
  • 가상 환경에서 발생하는 docker0 또는 172.x.x.x 등의 불필요한 IP가 반환되지 않도록 설계해 네트워크 환경과 프로그램 결과의 일관성을 확보하였습니다.

 


 

2. Ping 테스트의 반복 수행 및 정량화된 데이터 수집 기능 제공

  • ping3 라이브러리를 기반으로 특정 IP에 대해 지연 시간(RTT)을 다회 반복 측정합니다.
  • 각 시도로부터 다음 데이터를 자동 수집
    • 시도 번호
    • RTT(ms)
    • 성공 여부 또는 실패 원인(시간 초과 등)
  • 이를 통해 네트워크 품질을 정량적으로 평가할 수 있는 기반 데이터셋이 자동 생성합니다.

 


 

3. 측정 결과의 데이터프레임화 및 통계 처리 자동화

  • 모든 Ping 결과는 판다스(Pandas) 데이터프레임으로 구조화하여 분석 및 저장에 용이하도록 합니다.
  • 성공한 Ping들의 평균 RTT를 자동 계산하여 네트워크 품질에 대한 기초 통계 정보(평균 응답 시간)를 제공합니다.

 


 

4. Plotly 기반의 인터랙티브 Ping 시각화 그래프 제공

  • Plotly Express를 활용하여 RTT 변동 그래프를 실시간 생성 및 렌더링합니다.
  • 기능적 특징
    • RTT 변화의 직관적 관찰이 가능한 선 그래프
    • Hover 기능을 통한 정확한 수치 확인
    • 평균 RTT 기준선 자동 삽입
    • Dark 테마 기반의 가독성 높은 UI - 사실 개인 취향
  • 이를 통해 단순한 텍스트 기반 Ping 결과가 아닌, 사용자 친화적인 시각 분석 환경을 제공합니다.

 


 

5. 네트워크 문제 진단에 적합한 독립 실행형 프로그램 제공

  • Docker·가상환경에서의 잘못된 IP 반환 이슈를 해결하고, 반드시 로컬 디바이스에서 실행됨을 전제로 설계하였습니다.
  • 단일 실행만으로 IP 탐지 → Ping 실행 → 데이터 수집 → 그래프 출력까지 전 과정이 자동 처리되어 연구실/현장 등에서 즉시 활용 가능하는 것이 최종 목표입니다.

 

코드 

 

import socket
import ping3
import pandas as pd
import plotly.express as px
import time

def get_local_ip():
    """
    로컬 디바이스의 실제 IP 주소를 반환하는 함수입니다.
    도커나 WSL 같은 가상 환경에서는 가상 인터페이스의 IP가 반환될 수 있기 때문에,
    외부 주소(8.8.8.8)에 소켓을 연결하여 시스템이 실제로 사용하는 네트워크 인터페이스를 확인하는 방식입니다.
    """
    s = None
    try:
        # UDP 소켓을 생성합니다.
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        
        # 구글 DNS(8.8.8.8)의 80번 포트로 연결을 시도합니다.
        # 실제로 패킷을 보내지는 않지만, OS는 이 연결을 위해 사용 가능한 네트워크 인터페이스를 선택합니다.
        s.connect(('8.8.8.8', 80))
        
        # 소켓이 사용 중인 IP 주소를 가져옵니다.
        local_ip = s.getsockname()[0]
        return local_ip

    except Exception:
        # 예외 발생 시 hostname 기반의 IP를 반환합니다.
        try:
            return socket.gethostbyname(socket.gethostname())
        except:
            # 모든 방법이 실패할 경우 localhost를 반환합니다.
            return "127.0.0.1"

    finally:
        # 소켓이 열려 있으면 닫습니다.
        if s:
            s.close()


def plotly_ping_and_graph(host, count=15):
    """
    특정 host(IP 주소)에 대해 Ping 테스트를 여러 차례 수행하고,
    그 결과를 기반으로 Ping 지연 시간 그래프를 생성하는 함수입니다.

    host: Ping을 수행할 대상 IP입니다.
    count: Ping을 반복 수행할 횟수입니다.
    """

    data_list = []  # Ping 결과 데이터를 저장할 리스트입니다.

    # ping3 옵션 설정입니다.
    # use_global_sock 옵션은 권장되지 않아 제거하였습니다.
    ping_options = {'timeout': 2}

    print(f"\n[{host}] (로컬 디바이스)에 핑 테스트를 {count}회 시도합니다...")

    # count 횟수만큼 반복하여 Ping을 수행합니다.
    for i in range(1, count + 1):

        # ping3.ping() 함수로 지연 시간을 측정합니다.
        delay = ping3.ping(host, **ping_options)

        status_text = f"시도 {i}/{count}: "

        # Ping 성공 시 delay는 float(초 단위)로 반환됩니다.
        if isinstance(delay, float):
            rtt_ms = delay * 1000  # 지연 시간을 밀리초 단위로 변환합니다.

            # 성공 데이터를 저장합니다.
            data_list.append({
                '시도 횟수': i,
                '지연 시간 (ms)': rtt_ms,
                '성공 여부': '성공'
            })

            print(status_text + f"응답 성공! RTT: {rtt_ms:.5f} ms")

        else:
            # Ping 실패 시 delay는 None 또는 에러 문자열이 반환됩니다.
            fail_reason = "타임아웃" if delay is None else "응답 실패"

            data_list.append({
                '시도 횟수': i,
                '지연 시간 (ms)': None,
                '성공 여부': fail_reason
            })

            # Raw Socket 권한 필요 오류 처리입니다.
            if delay == "NeedRootPrivilege":
                print("\n\n❌ 치명적 오류 발생: Raw Socket 권한이 필요합니다.")
                print("ping3 라이브러리 최신 버전 업데이트 또는 관리자 권한 실행이 필요합니다.")
                return False

            print(status_text + f"{fail_reason}")

        # Ping 사이에 0.5초 간격을 둡니다.
        time.sleep(0.5)

    # 수집된 데이터를 판다스 데이터프레임으로 변환합니다.
    df = pd.DataFrame(data_list)

    # 성공한 Ping만 모아 평균 RTT를 계산합니다.
    successful_pings = df[df['성공 여부'] == '성공']['지연 시간 (ms)']

    if successful_pings.empty:
        print(f"\n❌ [{host}] 모든 Ping 시도가 실패했습니다.")
        return False

    avg_rtt = successful_pings.mean()

    # Plotly Express로 지연 시간 그래프를 생성합니다.
    fig = px.line(
        df.dropna(subset=['지연 시간 (ms)']),  # 성공한 데이터만 그래프에 표시합니다.
        x='시도 횟수',
        y='지연 시간 (ms)',
        title=f"로컬 디바이스 Ping 지연 시간 분석: {host}",
        markers=True,
        color_discrete_sequence=['#1E90FF']
    )

    # 그래프 레이아웃 설정입니다.
    fig.update_layout(
        xaxis=dict(
            tickmode='linear',
            dtick=1,
            range=[0.5, count + 0.5]
        ),
        yaxis_title="지연 시간 (ms)",
        hovermode="x unified",
        template="plotly_dark",
        title={
            'text': f"로컬 디바이스 Ping 지연 시간 분석: {host}",
            'y': 0.95,
            'x': 0.5,
            'xanchor': 'center',
            'yanchor': 'top',
            'font': {'size': 24, 'color': 'white'}
        },
        font={
            'family': 'Arial, sans-serif',
            'color': 'white'
        }
    )

    # Hover 텍스트 및 선 스타일 설정입니다.
    fig.update_traces(
        hovertemplate="시도: %{x}<br>지연 시간: %{y:.5f} ms<extra></extra>",
        line=dict(shape='spline', smoothing=1)
    )

    # 평균 RTT를 나타내는 수평선 추가입니다.
    fig.add_hline(
        y=avg_rtt,
        line_dash="dash",
        line_color="#FF4500",
        annotation_text=f"평균 RTT: {avg_rtt:.5f} ms",
        annotation_position="top right"
    )

    fig.show()
    return True


# ------------------------------
# 프로그램 실행 시작 부분입니다.
# ------------------------------
if __name__ == "__main__":

    # 로컬 디바이스의 실제 IP 주소를 자동으로 탐지합니다.
    local_ip_address = get_local_ip()

    print("--- 로컬 디바이스 정보 ---")
    print(f"자동 감지된 로컬 IP 주소: {local_ip_address}")
    print("----------------------------\n")

    # 해당 IP 주소를 대상으로 Ping 테스트를 수행합니다.
    plotly_ping_and_graph(local_ip_address, count=15)

 

- 깃허브 주소 : https://github.com/lko9911/Test_app_ping_check

 

GitHub - lko9911/Test_app_ping_check

Contribute to lko9911/Test_app_ping_check development by creating an account on GitHub.

github.com

 

 

실행 결과

 

코드 실행 결과

 

※ 이 코드는 Windows 로컬 환경에서 실제 IPv4 주소를 가져와 Ping 테스트를 수행하는 프로그램입니다.


Docker 환경이나 별도의 컨테이너에서 실행할 경우, 컨테이너 내부의 가상 네트워크 인터페이스(IP)가 반환되므로 정확한 로컬 디바이스 정보를 얻을 수 없습니다.  


 

참고 자료

 

 

[컴퓨터 네트워크] 핑 개념

💡 핑 (Ping)의 의미 핑(Ping)은 컴퓨터 네트워크에서 어떤 호스트(Host, 컴퓨터나 서버)가 현재 접속 가능한 상태인지, 그리고 데이터를 주고받는 데 걸리는 시간(지연 시간)이 얼마나 되는지를 확

whitecode2718.tistory.com