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

bool NetIsOK()

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

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

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netdb.h>
#include <errno.h>
#define MAX_WAIT_TIME   1
#define MAX_NO_PACKETS  1
#define ICMP_HEADSIZE 8
#define PACKET_SIZE     4096
struct timeval tvsend,tvrecv;
struct sockaddr_in dest_addr,recv_addr;
int sockfd;
pid_t pid;
char sendpacket[PACKET_SIZE];
char recvpacket[PACKET_SIZE];//函数定义
void timeout(int signo);
unsigned short cal_chksum(unsigned short *addr,int len);
int pack(int pkt_no,char *sendpacket);
int send_packet(int pkt_no,char *sendpacket);
int recv_packet(int pkt_no,char *recvpacket);
int unpack(int cur_seq,char *buf,int len);
void tv_sub(struct timeval *out,struct timeval *in);
void _CloseSocket();bool NetIsOk()
{     double rtt;struct hostent *host;struct protoent *protocol;int i,recv_status;#ifdef _USE_DNS //如果定义该宏,则可以使用域名进行判断网络连接,例如www.baidu.com/* 设置目的地址信息 */char hostname[32];sprintf(hostname,"%s","www.baidu.com")bzero(&dest_addr, sizeof(dest_addr));dest_addr.sin_family = AF_INET; if((host=gethostbyname(hostname))==NULL) {printf("[NetStatus]  error : Can't get serverhost info!\n");return false;}bcopy((char*)host->h_addr,(char*)&dest_addr.sin_addr,host->h_length);
#else //如果不使用域名,则只能用ip地址直接发送icmp包,例如谷歌的地址:8.8.8.8dest_addr.sin_addr.s_addr = inet_addr("8.8.8.8");
#endifif ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) { /* 创建原始ICMP套接字 */printf("[NetStatus]  error : socket");return false;}int iFlag;if(iFlag = fcntl(sockfd,F_GETFL,0)<0){printf("[NetStatus]  error : fcntl(sockfd,F_GETFL,0)");_CloseSocket();return false;}iFlag |= O_NONBLOCK;if(iFlag = fcntl(sockfd,F_SETFL,iFlag)<0){printf("[NetStatus]  error : fcntl(sockfd,F_SETFL,iFlag )");_CloseSocket();return false;}pid=getpid();for(i=0;i<MAX_NO_PACKETS;i++){       if(send_packet(i,sendpacket)<0){printf("[NetStatus]  error : send_packet");_CloseSocket();return false;}   if(recv_packet(i,recvpacket)>0){_CloseSocket();return true;}} _CloseSocket();        return false;
}int send_packet(int pkt_no,char *sendpacket)
{    int packetsize;       packetsize=pack(pkt_no,sendpacket); gettimeofday(&tvsend,NULL);    if(sendto(sockfd,sendpacket,packetsize,0,(struct sockaddr *)&dest_addr,sizeof(dest_addr) )<0){      printf("[NetStatus]  error : sendto error");return -1;}return 1;
}int pack(int pkt_no,char*sendpacket)
{       int i,packsize;struct icmp *icmp;struct timeval *tval;icmp=(struct icmp*)sendpacket;icmp->icmp_type=ICMP_ECHO;   //设置类型为ICMP请求报文icmp->icmp_code=0;icmp->icmp_cksum=0;icmp->icmp_seq=pkt_no;icmp->icmp_id=pid;          //设置当前进程ID为ICMP标示符packsize=ICMP_HEADSIZE+sizeof(struct timeval);tval= (struct timeval *)icmp->icmp_data;gettimeofday(tval,NULL);icmp->icmp_cksum=cal_chksum( (unsigned short *)icmp,packsize); return packsize;
}unsigned short cal_chksum(unsigned short *addr,int len)
{       int nleft=len;int sum=0;unsigned short *w=addr;unsigned short answer=0;while(nleft>1)        //把ICMP报头二进制数据以2字节为单位累加起来{       sum+=*w++;nleft-=2;}if( nleft==1)       //若ICMP报头为奇数个字节,会剩下最后一字节.把最后一个字节视为一个2字节数据的高字节,这个2字节数据的低字节为0,继续累加{*(unsigned char *)(&answer)=*(unsigned char *)w;sum+=answer;}sum=(sum>>16)+(sum&0xffff);sum+=(sum>>16);answer=~sum;return answer;
}int recv_packet(int pkt_no,char *recvpacket)
{           int n,fromlen;fd_set rfds;FD_ZERO(&rfds);FD_SET(sockfd,&rfds);signal(SIGALRM,timeout);fromlen=sizeof(recv_addr);alarm(MAX_WAIT_TIME);while(1){select(sockfd+1, &rfds, NULL, NULL, NULL);if (FD_ISSET(sockfd,&rfds)){  if( (n=recvfrom(sockfd,recvpacket,PACKET_SIZE,0,(struct sockaddr *)&recv_addr,&fromlen)) <0){   if(errno==EINTR)return -1;perror("recvfrom error");return -2;}}gettimeofday(&tvrecv,NULL); if(unpack(pkt_no,recvpacket,n)==-1)continue;return 1;}
}int unpack(int cur_seq,char *buf,int len)
{    int iphdrlen;struct ip *ip;struct icmp *icmp;ip=(struct ip *)buf;iphdrlen=ip->ip_hl<<2;     //求ip报头长度,即ip报头的长度标志乘4icmp=(struct icmp *)(buf+iphdrlen);     //越过ip报头,指向ICMP报头len-=iphdrlen;        //ICMP报头及ICMP数据报的总长度if( len<8)return -1;       if( (icmp->icmp_type==ICMP_ECHOREPLY) && (icmp->icmp_id==pid) && (icmp->icmp_seq==cur_seq))return 0;   else return -1;
}void timeout(int signo)
{printf("Request Timed Out\n");
}void tv_sub(struct timeval *out,struct timeval *in)
{       if( (out->tv_usec-=in->tv_usec)<0){       --out->tv_sec;out->tv_usec+=1000000;}out->tv_sec-=in->tv_sec;
}void _CloseSocket()
{close(sockfd);sockfd = 0;
}

linux下判断网络是否连接相关推荐

  1. Linux下的网络远程安装

    Linux下的网络远程安装 1.用RHEL6.5光盘安装第一台服务器 2.在第一台服务器上配置YUM服务器 先创建一个挂载 1 #mount 2 #umount /dev/cdrom 3 #mkdir ...

  2. Linux 下的网络配置

    #######linux下的网络配置############ ###1.什么是IP ADDRESS     internet protocol ADDRESS    ##网络进程地址         ...

  3. linux下的网络聊天室

    linux下的网络聊天室 一版:多reactor模式实现高并发服务器. sever.c #include "msg.h" #include "pthreadpool.h& ...

  4. 11 linux下的网络配置

    11 linux下的网络配置 1.IP ADDRESS是网络进程地址,ip是由32个01组成 2.子网掩码 用来划分网络区域 子网掩码非0的位对应的ip上的数字表示这个ip的网络位 子网掩码0位对应的 ...

  5. Linux下的网络配置[ dhcp]

    文章目录 一.Linux下的网络配置 1.以太网 2. 网络地址 IP ADDRESS 3. 子网掩码 4. ip通信判定 5.网络设定工具 5.1 ping 5.2 ifconfig(可临时设定ip ...

  6. linux下判断文件和目录是否存在[总结]

    原文地址为: linux下判断文件和目录是否存在[总结] 1.前言 工作中涉及到文件系统,有时候需要判断文件和目录是否存在.我结合APUE第四章文件和目录,总结一下如何正确判断文件和目录是否存在,方便 ...

  7. android中怎么网络判断,Android中判断网络是否连接实例详解

    Android中判断网络是否连接实例详解 在android中,如何监测网络的状态呢,这个有的时候也是十分重要的,方法如下: public class ConnectionDetector { priv ...

  8. Linux下检测网络状态是否正常

    // Linux下检测网络状态是否正常 #include <sys/types.h> #include <string.h> #include <stdlib.h> ...

  9. linux上mysql允许远程连接,linux下mysql允许远程连接

    1. MySql安装教程 https://dev.mysql.com/doc/refman/5.7/en/linux-installation-yum-repo.html 默认情况下mysq的 roo ...

最新文章

  1. 关于热插拔usb hotplug /proc/sys/kernel mdev udev busybox
  2. 实战SSM_O2O商铺_07【商铺注册】DAO层-新增与更新商铺
  3. 在Linq to Sql中管理并发更新时的冲突(3):使用记录的时间戳进行检测
  4. 深入浅出学习Struts框架(九):分析Struts框架实例4
  5. 5道谷歌面试题:即使是天才也要怀疑自己能力了(附答案)
  6. ssh(Spring+Spring mvc+hibernate)——hibernate.cfg.xml
  7. iangularjs 模板,AngularJS模板中的三元运算符
  8. 基于 Spring 实现管道模式的最佳实践
  9. pycharm检测不到python编译器_1.2 搭建python+pycharm编程开发环境
  10. 企业微信扫码登录流程
  11. esp8266 继电器接线图_基于ESP8266的温控继电器
  12. 诚龙网刻报错_诚龙网刻图文教程
  13. 揭开MySQL数据库的神秘面纱!
  14. 0-1背包问题和部分背包(fractional knapsack)问题分析(动态规划,贪心算法)
  15. MySQL事务与存储引擎
  16. c语言计算个人成绩平均分,C语言 | 计算总平均分及第n个人的成绩
  17. antd菜单使用动态图标
  18. Intel核显--OpenCL环境--Linux
  19. 又一篇Android Recovery的文章
  20. 百度松果 买礼物(贪心)

热门文章

  1. 5g通用模组是什么_中国联通发布《5G通用模组白皮书V2.0》
  2. 变频器说明书_图解变频器接线方法
  3. 将任何变量的值进行二进制输出的方法
  4. rust全息要啥才能做_在 Rust 中不能做什么
  5. myeclipse的电商系统模板_电商市场分析怎么做?3分钟了解程序员必备分析软件...
  6. 广州大学计算机技术复试c语言试题,广州大学C语言程序设计期末考试试卷含答案...
  7. java 回收器_Java虚拟机-经典垃圾回收器
  8. Python刷题-7
  9. oracle使用游标批量删除数据,oracle 游标批量处理数据
  10. java ide下载_jGRASP|轻量级Java IDE(jGRASP)下载v2.0.4.03官方版 - 欧普软件下载