여러대의 컴퓨터에 ping을 날리는 프로그램 구현에 관해서
글쓴이: cjy1126 / 작성시간: 금, 2003/04/18 - 5:08오후
제가 ping probe를 짜는중입니다.
현재 ping는 잘 동작하는데, select쪽 구현이 힘드네요.
원래는 db에서 ip를 긁어와서 그 ip들로 ping을 쏘고, 살아있는것을 다른 사람에게 보내주는 것이나 지금은 테스트용으로 linked list를 사용하였습니다.
지금 생각한 방법이 polling과 쓰레드, select 인데, polling은 가능하면 안쓸려고하고, select는 구현을 못하고 있습니다.
쓰레드는 2개의 쓰레드를 만들어서 하나는 ping을 보내기만하고 하나는 받기만 하려고하는데, 둘다 같은 소켓을 쓰니까 읽기와 쓰기가 동시에 일어나면 뻑날 수도 있어서 못쓰고...
select는 rset과 wset을 써야할텐데, wset은 안써봐서요.
지금 나름대로 구현한것인데... send만하고 recv를 하나도 못하다가 5초후에 SIGALRM으로 종료되네요. ㅜ.ㅜ
에러나 그런부분은 제가 어떻게든 하겠습니다.
어떤식으로 구현해야할지 구현방법에 대한 힌트 부탁드리겠습니다.
ping.h에는 signal처리(exit(0))와 NODE 구조체, icmp의 체크섬이 들어있습니다.
실제 중요한부분은 send_icmp()와 recvfrom() 부분 구현이라 생각됩니다.
#include "ping.h" char send_buf[1500]; //ping을 보내는 버퍼 char recv_buf[1500]; //ping을 받는 버퍼 int g_id = 0; //getpid() 값이 들어갈 부분 icmp의 identifier 부분 int g_seq = 0; //icmp의 sequence 부분 int sockfd; // ping를 보내고 받는 raw 소켓 struct sockaddr_in dest_addr; // 보낼 주소 구조체 struct sockaddr_in src_addr; // 받은 주소 구조체 char str[10][16] = { "192.168.3.90", "192.168.3.91", "192.168.3.92", "192.168.3.93", "192.168.3.94", "192.168.3.95", "192.168.3.96", "192.168.3.97", "192.168.3.98", "192.168.3.99" }; //보낼곳의 ip들 NODE *head, *tail; int init() //전체 초기화 부분 { int i; g_id = getpid(); init_node(); //linked list 초기화 부분 for(i=0; i<10; i++) insert_node(str[i]); //str 배열을 링크드 리스트에 삽입 signal(SIGALRM, sig_alrm); // SIGALRM 발생시 sig_alrm 함수로... // sig_alrm은 모든 ping을 다보내고 block된 recvfrom 풀기용으로 exit(0) 구문만 있음. memset(&dest_addr, 0, sizeof(struct sockaddr_in)); dest_addr.sin_family = AF_INET; dest_addr.sin_port = 0; return TRUE; } void init_node(void) //노드의 초기화 부분 { head = (NODE *)malloc(sizeof(NODE)); tail = (NODE *)malloc(sizeof(NODE)); head->next = tail; head->prev = head; tail->next = tail; tail->prev = head; } NODE *insert_node(char str[]) //ip의 삽입부분 { NODE *s; s = (NODE *)malloc(sizeof(NODE)); strcpy(s->addr, str); tail->prev->next = s; s->prev = tail->prev; s->next = tail; tail->prev = s; return s; } int send_icmp()//중요부분... { static int i=0; struct icmphdr *icmp; NODE *s; for(s=head->next; s!=tail; s=s->next){ //노드의 처음부터 끝까지 icmp = (struct icmphdr *)send_buf; icmp->type = ICMP_ECHO; icmp->code = 0; icmp->un.echo.id = g_id; icmp->un.echo.sequence = g_seq++; icmp->checksum = 0; icmp->checksum = icmp_cksum((unsigned short *)icmp, 16); dest_addr.sin_addr.s_addr = inet_addr(s->addr);//목적지 ip가 계속 바뀐다. if(sendto(sockfd, send_buf, 16, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr))<0) perror("sendto: "); //보낸 ping의 sequence와 아이피 출력 printf("%d send %s\n", icmp->un.echo.sequence, inet_ntoa(dest_addr.sin_addr.s_addr)); } //여기까지 왔다면 ip를 다 보낸것으로 5초간 ping을 기다리고 안오면 alarm을 발생시켜 프로그램을 종료시킨다. alarm(5); return TRUE; } void recv_icmp(char *buf, int totlen)// icmp분석부분... { int iplen, icmplen; struct iphdr *ip; struct icmphdr *icmp; int i, j; ip = (struct iphdr *)buf; iplen = ip->ihl*4; icmp = (struct icmphdr *)(buf + iplen); if(icmp->type == ICMP_ECHOREPLY){ if(icmp->un.echo.id == g_id) { //도착한 sequence나 ip 기록... } } } int main() { int len, sz; init();//초기화부분 if((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP))<0){ fprintf(stderr, "ERROR: Opening raw socket. (need UID 0)\n"); exit(0); } send_icmp();//linked list에 있는 모든 핑을 보내는 부분 while(1) { memset(recv_buf, '\0', sizeof(recv_buf)); len = sizeof(src_addr); //reply ping을 받는다. if((sz=recvfrom(sockfd, recv_buf, sizeof(recv_buf), 0, (struct sockaddr *)&src_addr, &len))<=0) { if(errno == EINTR) continue; else perror("recv from: "); } recv_icmp(recv_buf, sz); //받은 ping을 분석 } }
Forums:
[code:1]signal(SIGALRM, sendping&#
위의 코드는 일반적인 ping program을 참조한것입니다.
sendping이란 함수에서 send icmp를 담당하게 하고 시스템 에 설정된 시간마다 함수를 실행 시켜주는 거죠.. pingstats는 결과입니다.
그리고 보낸 icmp packet의 개수가 정의된 개수를 넘어가면 결과를 보여주고 종료하는거죠.. 쓰레드에 다음과 같은 routine을 넣어주면 알아서 죽~ 돌아가겠네요.. (근데 쓰레드 돌릴 필요가 있는걸지?? list까지 사용하면 필요없을거 같은데. ^^a)
받는부분은 icmp packet내에 id가 있기 때문에 루프돌며 계속 recvfrom해주면 쉽게 구분이 가능할거고요..
그럼이만..
평온하다~
ping를 받을 컴퓨터를 1000대정도로 잡았거든요.
send하는동안 recv를 못받아도 안되고, recv에서 블록이 걸려도 안됩니다.
그렇다고 recv를 non-block로해서 polling도 안되고...
지금 send와 recv하는 쓰레드 2개를 돌리는것을 구현하고 있는데, 계속 에러만 나네요.
문제는 마지막 컴퓨터에 ping을 send하고 5초정도 후에 이 작업이 종료되어야하는데, recv 쪽 쓰레드를 얼케 보낼지? -_-;
signal(SIGALRM)으로해서 exit(0)했더니, 함수로 제공해줘야해서 exit(0)를 쓰면 안된다네요. ㅜ.ㅜ
그리고 ping에대해서 reply한 놈들의 ip를 linked list로 보내야하는데... 정말 난감하네요.
nms에서 ping probe 구현해보신분 조언 부탁드리겠습니다.
전 댓수가 적어서
전 댓수가 적어서 그런지 몰라도 그냥 shell에서
ping xxx.xxx.xxx.xxx -c 1 | grep 으로 했습니다.
1000대면 많기는 하군요.. ㅋㅋ
인생의 무게를 느껴라. 아는 만큼 보이는게다.
nms 에서 ping probe 를
nms 에서 ping probe 를 구현한 것은 아니구요.
iptables 에서 제공하는 queue 를 이용해서 SYN 패킷에 대해서 300ms 이내에 ping 체크를 해야할 때 만들었던 프로그램인데.. 훔훔.
넌블럭킹은 아니고 timeout 을 체크하기 위해 select 를 쓴 소스입니다. cjy1126 님이 짜신 소스와 크게 차이는 없어 보이는군요.
wooix 님이 말씀하신 id 부분은 글쎄요. 유니크한 값인가요 ?
제가 테스트 했을때는 id 값이 유니크한 값이 아니어서 id 로는 체크를 하지 않았습니다.
ps
1. 천대를 한 순간에 다 체크하실 건 아니죠 ? ㅡ.ㅡ;;;
2. 지금 다시 보니 소스가 무쟈게 조잡하네요. 여기저기 짜집기한것들도 꽤 많고... 적당히 필터링하시면서 봐 주세요~
nms 에서 ping probe 를
왜 3개나 올라갔는지.. ㅡ.ㅡ;;
댓글 삭제 버튼 어디있는지 알려주시면 감사하겠습니다. (__);;;
nms 에서 ping probe 를
엇어... 3개나 올라갔네요. 삭제는 어떻게 하죠 ㅡ.ㅡ;;
http://fping.sourceforge.net/
http://fping.sourceforge.net/
-------------------------------------------------------------------------------------------------------
Life ... http://iz4u.net/blog/
------------------------------------------------------------------------------------------------
Life is in 다즐링
댓글 달기