ioerror

[Python]여러 개의 호스트에 Ping을 날리고 평균값 저장하기 본문

Python

[Python]여러 개의 호스트에 Ping을 날리고 평균값 저장하기...

반응형

 

상황

인터넷이 느리다. PING을 보면 손실률이 들쭉날쭉 마음대로다. 특정 시간대에 손실률이 많은 것인지 아니면 평균적으로 손실률이 많은 것인지  측정해보고 싶어 졌다.

 

여하튼 만들고자 하는 기능은

  • 여러 개의 호스트로 핑을 일정 회수로 테스트한다.
    각 지점에서 주요 서버로 핑 테스트를 해야 한다.
  • 일정 시간 간격으로 핑을 실행하고 평균값을 기록한다.
    신뢰성 있는 핑 값을 구하기 위해 여러 번 실행하고, 시간대별 손실률이 얼마인지 각 지역에서의 동일 시간대에 네트워크 상태가 어떤지 확인을 위해 실행하고 피씨가 켜져 있는 동안 일정 시간 동안 주기적으로 작동해야 한다.

어쩌면 그냥 커맨드 창에서 ping -t {IP} 하면 되지 않냐고 하겠지만 각 지역별 직원에게 매 시간대에 핑을 날리고 값을 기록해달라 하면 안 그게 뭔가요? 몰라서 못하겠어요 라는 답변이 돌아올 것이기에 그냥 파일 던져 주고 실행하시고 퇴근 전에 텍스트 파일만 주시면 됩니다. 하려고 만든다.

 

이 뭔 개소리인가?

 

어찌 되었든 간에 파이썬으로 문제를 해결하기 위해 구글링 하면서 만들어 봤다.

 

1. 파이썬 설치

피씨에 설치된 파이썬은 2 버전인데 아래에 언급하겠지만 pyinstaller와 apschedule를 pip로 설치할려니 오류가 났다.

그래서 지우고 3 버전으로 재설치하는데 기본 설치경로가( C:\User\{NAME}\AppData... ) 마음에 들지 않아서 C:\Python3으로 설정하고 설치를 했으나 곧 후회하게 되는데.... 뭐든지 순정이 좋은 것이다.

 

2. 먼저 핑을 어떻게 실행해야 하는가?

찾아보니 subprocess 라는 것을 이용하면 된다고 해서 그냥 구글링 해서 나온 걸로 코딩했다.

핑 옵션도 다양하다는 것을 새삼 다시 알게 되었다. 다음에 한번 정리를 해야겠다.

# ping -n 100 192.168.1.1 -> 핑을 입력한 ip로 100번 실행 하라는 것
command = ['ping', '-n', '100', host]
subprocess.Popen(command, shell=True, stdout=subprocess.PIPE).stdout 

 

3. 일정 시간마다 실행하기?

이를 위해서는 어떤 절차로 구동되어야 할지 생각해야 한다.

첫 번째는 무한 루프를 돌고 time.sleep, 그리고 시간을 확인해서 핑을 하는 방법을 생각했으나 아무리 처음 만드는 파이썬이라지만 이건 아니다 싶어서 찾아보니 apscheduler라는 것을 이용하면 cron 또는 interval 방식으로 스케쥴링할 수 있다.

pip install apscheduler

나중에 pyinstaller로 실행 파일을 만들 때 apscheduler의 cron 방식 사용 때문에 아래의 오류가 발생했다.

pyinstaller lookuperror: no trigger by the name "cron" was found

이건 개소리인 건지 검색을 해봐도 나오지 않았다. 신기한 건 중국 쪽 개발자들은 이 현상을 경험했는지 구글 검색에 몇 개가 나온다.

구글 그룹에 보니 CronTrigger를 사용해야 된다 해서 임포트하고 수정을 하니 잘된다.

# apscheduler를 위한 모듈을 가져온다.
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.jobstores.base import JobLookupError
from apscheduler.triggers.cron import CronTrigger

# 백그라운드 스캐듈링 생성
sched = BackgroundScheduler()

'''
처음에는 아래와 같이 코딩 했는데 cron 관련 오류로 인해 CronTrigger를 사용했다.
sched.add_job(pingtest, 'cron', minute='*/5', end_date="2020-05-28 21:20:00", id="ping_schedule")
'''

#문제의 cron 트리거 생성
trigger = CronTrigger(minute="*/30")
# 핑테스트 대상 호스트(host)개수 만큼 스케쥴 생성
for host in arr_hosts:
	sched.add_job(핑실행함수, trigger, [host], id=host+ctime, max_instances=10)
# 스케쥴 시작
sched.start()

'''
아래는 상태 화면 출력 및 일정 시간이 되거나 키 입력시 종료 
'''
try:
	while end == False:
    	now = time.localtime()
		hour_now = "%02d:%02d:%02d" % (now.tm_hour, now.tm_min, now.tm_sec)
		onproc = "  ".join(arr_onproc_host)
		print("wating "+ctime+" / " + hour_now +" ("+onproc+")")
		if now.tm_min >= 25 and now.tm_hour == 22:
			print("완료")
			end = True
			for host in arr_hosts:
				sched.remove_job(host+ctime)
		time.sleep(1)
except (KeyboardInterrupt, SystemExit):
	sched.shutdown()

 

4. 그런데 로그는 어떻게 기록하지?

이제 기본 기능은 갖추어졌다. 핑을 날릴 수 있고, 일정 시간마다 실행할 수 있다. 그런데 로그를 텍스트 파일에 어떻게 저장하지?

검색을 해서 처음 찾은 결과는 화면 출력되는 것을 파일에 바로 입력하는 것인데, with 이렇게 하니 뭔가.. 느리다 해야 하나? 프로세스들 간에 충돌? 뭐 그런 현상이 나타나는 것인지 불안정했다. 중간중간에 멈춤 현상이나 apscheduler의 max instance를 뱉어 낸다거나.

그래서 찾은 코드가 

out = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE).stdout

subprocess의 결과를 PIPE를 통해 stdout으로 토해내서 out에 저장한다... 정도라만 이해를 하자.

그리고 하는 김에 os.makedirs로 로그를 기록할 디렉터리도 만들었다.

 

5. 실행파일 만들기!!!

일반 중생들이 Python을 주머니에 넣고 다니지는 않잖아?!

pip install pyinstaller

드디어 pyinstaller 를 설치 했다, 아니 설치를 시도 했으나 실패!, pip를 업그레이드 해봤으나 실패! 파이썬 설치 경로 문제인가? 윈도우 환경설정에 파이썬 설치 경로 추가, 다시 설치 진행. 실패!

다시 구글신께 문의하니... 그냥 공식 사이트에서 다운받아서 설치하라신다.

https://www.pyinstaller.org/downloads.html 접속해서 파일 다운로드, 압축을 풀고 나서 pyinstaller.py 실행. 설치 완료!

끝!

실행 파일 만들때 --onefile 옵션을 주면 dist 디렉토리에 하나의 실행 파일이 생성된다. 옵션을 주지 않으면 각종 모듈 등 링커 파일들이 생겨난다. 

pyinstaller --onefile file.py 

 

6. TaDa~ 최종 파일

pinghosts.py

import os
import time
import subprocess
import sys
import socket

from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.jobstores.base import JobLookupError
from apscheduler.triggers.cron import CronTrigger

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) #3 
s.connect(('8.8.8.8', 0)) 
myip = s.getsockname()[0] 

now = time.localtime()
ctime = time.localtime(time.time() + 60)
ctime = str(ctime.tm_min)
print(ctime)

arr_hosts = ["hq.korea.com","branch.china.com","192.168.1.1"]
arr_onproc_host = {}

end = False

logpath = "./pinglog"

def pingloging(host):
    global myip,ctime
    now = time.localtime()
    time_start = "%02d:%02d:%02d" % (now.tm_hour, now.tm_min, now.tm_sec)
    filename = os.path.join(logpath, "pingtest_"+ctime+"_"+myip+"___"+host +".txt")
    arr_onproc_host[host] = host
    command = ['ping', '-n', '100', host]
    print("ping start : "+time_start+" / "+myip+" -> "+host)
    out = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE).stdout 
    buffers = out.read().strip()
    out.close()
    buffers = buffers.decode('cp949', 'ignore')
    buff_str = str(buffers)
    buff_arr = buff_str.split("\n")
    buff_len = len(buff_arr)
    buff_log = [buff_arr[buff_len-5], 
    			buff_arr[buff_len-4], 
                buff_arr[buff_len-3], 
                buff_arr[buff_len-2], 
                buff_arr[buff_len-1]]
    buff = "\n".join(buff_log)
    f = open(filename,'a')
    f.write("\n\n####################\n")
    f.write(myip+"->"+ host+"\n"+time_start+"\n")
    f.write(buff)
    now = time.localtime()
    time_end = "%02d:%02d:%02d" % (now.tm_hour, now.tm_min, now.tm_sec)
    f.write("\n\n"+time_end+"\n"+myip+"->"+ host+"\n")
    f.write("==================\n\n\n")
    f.close()
    del arr_onproc_host[host]
    print("ping end : "+time_start+" -> "+time_end+" / "+myip+" -> "+host)
    return

def startping():
    global end,arr_hosts,arr_onproc_host
    now = time.localtime()
    if now.tm_min >= 25 and now.tm_hour == 22:
        print("실행시간외")
        return
    if not(os.path.isdir(logpath)):
        os.makedirs(os.path.join(logpath))

    sched = BackgroundScheduler()
    trigger = CronTrigger(minute="*/30")
    for host in arr_hosts:
        sched.add_job(pingloging, trigger, [host], id=host+ctime, max_instances=10)
    
    sched.start()
    
    try:
        while end == False:
            now = time.localtime()
            hour_now = "%02d:%02d:%02d" % (now.tm_hour, now.tm_min, now.tm_sec)
            onproc = "  ".join(arr_onproc_host)
            print("wating "+ctime+" / " + hour_now +" ("+onproc+")")
            if now.tm_min >= 25 and now.tm_hour == 22:
                print("완료")
                end = True
                for host in arr_hosts:
                    sched.remove_job(host+ctime)
            time.sleep(1)
    except (KeyboardInterrupt, SystemExit):
        sched.shutdown()    
    return

startping()

 

 

반응형

'Python' 카테고리의 다른 글

파이썬 PPT 파일 내용 검색하기  (0) 2021.04.16
Comments