ntp 클라이언트에서 서버 접속 관리 (select, alarm 등)
임베디드 환경에 사용할 ntpclient를 테스트 중입니다.
http://doolittle.icarus.com/ntpclient/ 에서 다운로드 받았고,
컴파일 및 실행은 잘 됩니다.
ntpclient -h time.bora.net -d -s -i 15 &
위 명령을 수행하면 해당 NTP 서버에 15초마다 접속하여 시스템의 시간을 설정합니다.
현재 임베디드 시스템에 cron 같은 명령이 지원되지 않는 것 같은데 저렇게 백그라운드로 실행하면
내부적으로 15초마다 실행(select의 timeout 이용)되어서 그냥 저렇게 사용할까 합니다.
문제는 유사시의 경우입니다.
1. 특정 NTP 서버가 연결이 안 될 때
2. NTP 서버들의 주소가 변경되어야 할 때.
(여기서 서버 주소 변경은 NTP 서버 리스트 파일을 외부 프로그램이 수정하는 경우를 생각하고 있습니다.)
3. 임베디드 기기의 네트워크 자체가 안 될 때..
1번의 경우에 대비해서는 NTP 서버 리스트 파일(ex. ntp.conf)에 2개 이상의 서버 목록을 두고
첫번째 서버에서 응답이 없는 경우에 두번째 백업서버를 host로 해서 접속하려고 합니다.
(따라서 위 코드에서 -h 옵션은 없애도 되네요.)
alarm()을 이용해서 NTP 서버로부터 몇초간 응답이 없으면, 다른 서버로 ntp 패킷을 보내도록
ntp client 소스 자체를 고쳤고요. 나름 동작하는 것 같습니다.
2번의 경우는 NTP 서버 주소를 바꾸는 것이 외부 프로그램이기 때문에 그 외부 프로그램이
스크립트를 실행해서 killall ntpclient, 하고 ntp.conf 수정하고 다시 system() 함수로
위 명령을 실행하면 어떨까 하는 생각이 드네요.
그런데 마지막 3번의 경우 지금대로라면 NTP 서버와 connection을 연결할 때
error가 나서 프로그램이 종료가 될텐데요. 이를 어떻게 알고 새로 명령을 수행해 줄까 하는 문제가 있네요.
사실 네트워크가 되는데 NTP 서버가 불능에 빠질 경우보다, 기기 자체의 네트워크가 안 되는 상황이
더 빈번할 것 같은데요...
이 경우 스크립트로 (rc.d 아래두게 할..) 어떻게 할지는 감이 안 오는군요.
스크립트만으로 가능한지도 잘 가늠이 안 되어서요.
약간 경험 있으신 분의 힌트 좀 부탁드립니다.
덧/
매 주기마다 NTP 서버에 요청 패킷을 보내는 것이 대충 아래 코드와 같은데요.
이 안쪽에 alarm을 써서 NTP 서버로부터 응답이 없는 경우를 처리하도록 했습니다.(주석부분)
실제 코드는 약간 다르긴 하지만, 우려할만한 side effect는 없을까요?
fd_set fds; struct sockaddr sa_xmit; struct timeval to; to.tv_sec=0; to.tv_usec=0; for (;;) { FD_ZERO(&fds); FD_SET(usd,&fds); i=select(usd+1,&fds,NULL,NULL,&to); /* Wait on read or error */ if ((i!=1)||(!FD_ISSET(usd,&fds))) { if (i<0) { if (errno != EINTR) perror("select"); continue; } if (to.tv_sec == 0) { if (probes_sent >= ntpc->probe_count && ntpc->probe_count != 0) break; send_packet(usd,ntpc->time_of_send); alarm(2) // 2초후까지 응답 패킷 없으면 EINTR 발생 ++probes_sent; to.tv_sec=ntpc->cycle_time; to.tv_usec=0; } continue; } pack_len=recvfrom(usd,incoming,sizeof_incoming,0, &sa_xmit,&sa_xmit_len); alarm(0) // 패킷 받으면 alarm 셋팅 해제 ........ 후략 .........
참 ntp 서버 재설정 할 때는...
참 ntp 서버 재설정 할 때는...
와 같은 함수를 이용합니다. 이 때 connect에러가 날 때 어떻게 처리할까가 문제이네요.
inittab 의 respawn 에
inittab 의 respawn 에 등록하세요.
죽으면 재실행됩니다.
서버 리스트파일 수정 뒤 kill 만 하셔도 되겠고요.
다만, 예외상황에 의해 너무 자주 많이 죽으면 콘솔로 보기 싫은 메시지가 출력될 수도 있고,
어쩌면 init 이 강제로 비활성화 시킬 수도 있습니다.
OTL
답변 감사드립니다.
respawn에 등록하니 일단 init q로 해보면 실행되는 것은 확인할 수 있었습니다.
1. 해당 프로세스를 kill하고자 하는데 어떻게 해야할까요?
원래 기존 스크립트에서는 killall 이란 명령어를 썼었는데,
killall ntpclient 라고 실행해도 kill할 프로세스가 없다고만 나오네요.
inittab에 두니 ps -aux해도 ntpclient라는 프로세스가 안보이고요.
inittab에서는
정도로 작성을 했습니다.
2. 언급하신 사항인 것 같은데, 15초마다 시간을 동기화하는 것이 그렇게 빈번한 것인가요?
테스트를 위해 NTP 동기화 최소 시간인 15마다 시간을 받아와서 설정하게 했는데,
/var/log/messages에 Id "ns" respawning too fast: disbled 5 minutes라고 나오네요.
실제 사용시에는 5분, 10분 마다 동기화하려고 합니다만, 궁금하네요
1. ntpclient를 반복
1. ntpclient를 반복 실행하는것보다 ntpd를 돌리시는게 더 낫고
2. 15초는 너무 짧으네요. (5분, 10분도) 하루정도가 나을것 같습니다.
http://en.wikipedia.org/wiki/NTP_vandalism
--
익스펙토 페트로눔
--
익스펙토 페트로눔
네 답변 감사합니다.
임베디드 기기에서 사용하는데 원래는 ntpd나 ntpdate, ntptime 등의
바이너리가 있어서 사용을 해보기도 했습니다.
그런데 약간 다른 부분에서 유발된 문제가 있어서 ntpclient를 사용을 하게 된 것입니다.
/etc/services 쪽에서 설정된 ntp용 123번 포트를 프로그램에서 못 찾는 문제가 있어서
급히 피해가느라.. (getservbyname() 함수가 제대로 동작 안하는데 이유는 모르겠고, inetd도 잘 안 되고요.)
지금은 테스트 중이라 15초로 해본것이구요, 소스에서 default값이 600초이더군요.
추후에 사용시에는 시간 단위로 설정하게 될 것 같습니다.
댓글 달기