linux下C语言判断网络是否连接

本文改写自网上的一个程序,原始程序中为阻塞式调用,而且有进程创建的过程,非常不利于集成到自己程序中,因此对原始程序进行改造,使其可以完成发送一个imcp包的方式来判断网络连通,只需要调用改进后的

 bool NetIsOK()

函数即可,该函数返回true即表示网络状态良好,否则表示网络状态不连同,本程序中只发送了一个icmp包,在实际应用中可以根据需要改进为发送多个imcp包。

修改之后的程序为:只需要调用函数NetIsOK()即可。源码如下所示:

http://blog.csdn.net/houjixin/article/details/8843702

[cpp]  view plain  copy
  1. #include <stdio.h>  
  2. #include <signal.h>  
  3. #include <stdlib.h>  
  4. #include <fcntl.h>  
  5. #include <sys/types.h>  
  6. #include <sys/wait.h>  
  7. #include <sys/socket.h>  
  8. #include <unistd.h>  
  9. #include <netinet/in.h>  
  10. #include <netinet/ip.h>  
  11. #include <netinet/ip_icmp.h>  
  12. #include <netdb.h>  
  13. #include <errno.h>  
  14. #define MAX_WAIT_TIME   1  
  15. #define MAX_NO_PACKETS  1  
  16. #define ICMP_HEADSIZE 8   
  17. #define PACKET_SIZE     4096  
  18. struct timeval tvsend,tvrecv;     
  19. struct sockaddr_in dest_addr,recv_addr;  
  20. int sockfd;  
  21. pid_t pid;  
  22. char sendpacket[PACKET_SIZE];  
  23. char recvpacket[PACKET_SIZE];  
  24.   
  25. //函数定义  
  26. void timeout(int signo);  
  27. unsigned short cal_chksum(unsigned short *addr,int len);  
  28. int pack(int pkt_no,char *sendpacket);  
  29. int send_packet(int pkt_no,char *sendpacket);  
  30. int recv_packet(int pkt_no,char *recvpacket);  
  31. int unpack(int cur_seq,char *buf,int len);  
  32. void tv_sub(struct timeval *out,struct timeval *in);  
  33. void _CloseSocket();  
  34.   
  35. bool NetIsOk()  
  36. {       
  37.           
  38.     double rtt;  
  39.     struct hostent *host;  
  40.     struct protoent *protocol;  
  41.     int i,recv_status;  
  42.   
  43. #ifdef _USE_DNS //如果定义该宏,则可以使用域名进行判断网络连接,例如www.baidu.com  
  44.     /* 设置目的地址信息 */  
  45.     char hostname[32];  
  46.     sprintf(hostname,"%s","www.baidu.com")  
  47.     bzero(&dest_addr, sizeof(dest_addr));  
  48.     dest_addr.sin_family = AF_INET;   
  49.   
  50.     if((host=gethostbyname(hostname))==NULL)   
  51.     {  
  52.         printf("[NetStatus]  error : Can't get serverhost info!\n");  
  53.         return false;  
  54.     }  
  55.   
  56.     bcopy((char*)host->h_addr,(char*)&dest_addr.sin_addr,host->h_length);  
  57. #else //如果不使用域名,则只能用ip地址直接发送icmp包,例如谷歌的地址:8.8.8.8  
  58.     dest_addr.sin_addr.s_addr = inet_addr("8.8.8.8");  
  59. #endif  
  60.       
  61.   
  62.     if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)   
  63.     {   /* 创建原始ICMP套接字 */  
  64.         printf("[NetStatus]  error : socket");  
  65.         return false;  
  66.     }  
  67.   
  68.     int iFlag;  
  69.     if(iFlag = fcntl(sockfd,F_GETFL,0)<0)  
  70.     {  
  71.         printf("[NetStatus]  error : fcntl(sockfd,F_GETFL,0)");  
  72.         _CloseSocket();  
  73.         return false;  
  74.     }  
  75.     iFlag |= O_NONBLOCK;  
  76.     if(iFlag = fcntl(sockfd,F_SETFL,iFlag)<0)  
  77.     {  
  78.         printf("[NetStatus]  error : fcntl(sockfd,F_SETFL,iFlag )");  
  79.         _CloseSocket();  
  80.         return false;  
  81.     }  
  82.   
  83.     pid=getpid();  
  84.     for(i=0;i<MAX_NO_PACKETS;i++)  
  85.     {         
  86.       
  87.         if(send_packet(i,sendpacket)<0)  
  88.         {  
  89.             printf("[NetStatus]  error : send_packet");  
  90.             _CloseSocket();  
  91.             return false;  
  92.         }     
  93.   
  94.         if(recv_packet(i,recvpacket)>0)  
  95.         {  
  96.             _CloseSocket();  
  97.             return true;  
  98.         }  
  99.           
  100.     }   
  101.     _CloseSocket();           
  102.     return false;  
  103. }  
  104.   
  105.   
  106.   
  107. int send_packet(int pkt_no,char *sendpacket)  
  108. {      
  109.     int packetsize;         
  110.     packetsize=pack(pkt_no,sendpacket);   
  111.     gettimeofday(&tvsend,NULL);      
  112.     if(sendto(sockfd,sendpacket,packetsize,0,(struct sockaddr *)&dest_addr,sizeof(dest_addr) )<0)  
  113.     {        
  114.         printf("[NetStatus]  error : sendto error");  
  115.         return -1;  
  116.     }  
  117.     return 1;  
  118. }  
  119.   
  120.   
  121. int pack(int pkt_no,char*sendpacket)  
  122. {         
  123.     int i,packsize;  
  124.     struct icmp *icmp;  
  125.     struct timeval *tval;  
  126.     icmp=(struct icmp*)sendpacket;  
  127.     icmp->icmp_type=ICMP_ECHO;   //设置类型为ICMP请求报文  
  128.     icmp->icmp_code=0;  
  129.     icmp->icmp_cksum=0;  
  130.     icmp->icmp_seq=pkt_no;  
  131.     icmp->icmp_id=pid;           //设置当前进程ID为ICMP标示符  
  132.     packsize=ICMP_HEADSIZE+sizeof(struct timeval);  
  133.     tval= (struct timeval *)icmp->icmp_data;  
  134.     gettimeofday(tval,NULL);  
  135.     icmp->icmp_cksum=cal_chksum( (unsigned short *)icmp,packsize);   
  136.     return packsize;  
  137. }  
  138.   
  139.   
  140. unsigned short cal_chksum(unsigned short *addr,int len)  
  141. {         
  142.     int nleft=len;  
  143.     int sum=0;  
  144.     unsigned short *w=addr;  
  145.     unsigned short answer=0;  
  146.     while(nleft>1)       //把ICMP报头二进制数据以2字节为单位累加起来  
  147.     {         
  148.         sum+=*w++;  
  149.         nleft-=2;  
  150.     }  
  151.     if( nleft==1)       //若ICMP报头为奇数个字节,会剩下最后一字节.把最后一个字节视为一个2字节数据的高字节,这个2字节数据的低字节为0,继续累加  
  152.     {  
  153.         *(unsigned char *)(&answer)=*(unsigned char *)w;  
  154.         sum+=answer;  
  155.     }  
  156.     sum=(sum>>16)+(sum&0xffff);  
  157.     sum+=(sum>>16);  
  158.     answer=~sum;  
  159.     return answer;  
  160. }  
  161.   
  162.   
  163. int recv_packet(int pkt_no,char *recvpacket)  
  164. {             
  165.     int n,fromlen;  
  166.     fd_set rfds;  
  167.     FD_ZERO(&rfds);  
  168.     FD_SET(sockfd,&rfds);  
  169.     signal(SIGALRM,timeout);  
  170.     fromlen=sizeof(recv_addr);  
  171.     alarm(MAX_WAIT_TIME);  
  172.     while(1)  
  173.     {  
  174.         select(sockfd+1, &rfds, NULL, NULL, NULL);  
  175.         if (FD_ISSET(sockfd,&rfds))  
  176.         {    
  177.             if( (n=recvfrom(sockfd,recvpacket,PACKET_SIZE,0,(struct sockaddr *)&recv_addr,&fromlen)) <0)  
  178.             {     
  179.             if(errno==EINTR)  
  180.                 return -1;  
  181.                 perror("recvfrom error");  
  182.                 return -2;  
  183.             }  
  184.         }  
  185.         gettimeofday(&tvrecv,NULL);   
  186.         if(unpack(pkt_no,recvpacket,n)==-1)  
  187.             continue;  
  188.         return 1;  
  189.     }  
  190. }  
  191.   
  192. int unpack(int cur_seq,char *buf,int len)  
  193. {      
  194.     int iphdrlen;  
  195.     struct ip *ip;  
  196.     struct icmp *icmp;  
  197.     ip=(struct ip *)buf;  
  198.     iphdrlen=ip->ip_hl<<2;     //求ip报头长度,即ip报头的长度标志乘4  
  199.     icmp=(struct icmp *)(buf+iphdrlen);     //越过ip报头,指向ICMP报头  
  200.     len-=iphdrlen;      //ICMP报头及ICMP数据报的总长度  
  201.     if( len<8)  
  202.         return -1;         
  203.     if( (icmp->icmp_type==ICMP_ECHOREPLY) && (icmp->icmp_id==pid) && (icmp->icmp_seq==cur_seq))  
  204.         return 0;     
  205.     else return -1;  
  206. }  
  207.   
  208.   
  209. void timeout(int signo)  
  210. {  
  211.     printf("Request Timed Out\n");  
  212. }  
  213.   
  214. void tv_sub(struct timeval *out,struct timeval *in)  
  215. {         
  216.     if( (out->tv_usec-=in->tv_usec)<0)  
  217.     {         
  218.         --out->tv_sec;  
  219.         out->tv_usec+=1000000;  
  220.     }  
  221.     out->tv_sec-=in->tv_sec;  
  222. }  
  223.   
  224. void _CloseSocket()  
  225. {  
  226.     close(sockfd);  
  227.     sockfd = 0;  
  228. }  


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值