方法一:

  • windows下调用icmp.dll库,实现ping连通检测,缺点是不能跨平台,受限于icmp.dll库:
// windows下调用icmp.dll库实现网络连通检测示例代码#include <Winsock2.h>
#include <iphlpapi.h>
#include <stdio.h>#pragma comment(lib,"Iphlpapi.lib")
#pragma comment(lib,"Ws2_32.lib")
typedef HANDLE (WINAPI* ICMPCREATEFILE)(VOID);
typedef BOOL (WINAPI* ICMPCLOSEHANDLE)(HANDLE);
typedef DWORD (WINAPI* ICMPSENDECHO)(HANDLE, DWORD, LPVOID, WORD,PIP_OPTION_INFORMATION, LPVOID, DWORD, DWORD);    // 定义三个指针函数
ICMPCREATEFILE pIcmpCreateFile;
ICMPCLOSEHANDLE pIcmpCloseHandle;
ICMPSENDECHO pIcmpSendEcho; // 函数功能:初始化ICMP函数:
BOOL InitIcmp()
{   HINSTANCE hIcmp = LoadLibrary(TEXT("ICMP.DLL"));    // 需自行下载icmp.dll动态库if(hIcmp==NULL){   return false; }  pIcmpCreateFile = (ICMPCREATEFILE)GetProcAddress(hIcmp,"IcmpCreateFile");   pIcmpCloseHandle = (ICMPCLOSEHANDLE)GetProcAddress(hIcmp,"IcmpCloseHandle");   pIcmpSendEcho = (ICMPSENDECHO)GetProcAddress(hIcmp,"IcmpSendEcho");   if ((pIcmpCreateFile == NULL)||(pIcmpCloseHandle == NULL)||(pIcmpSendEcho == NULL))   return false;   return true;
}// 函数功能:判断是否能ping通IP
// 函数参数:IP地址或域名
BOOL ICMPPing(char* host)
{   DWORD timeOut=1000;                                    // 设置超时   ULONG hAddr=inet_addr(host);                           // 如果是IP地址就直接转换   if(hAddr==INADDR_NONE)   {   hostent* hp=gethostbyname(host);                   // 如果是域名就用DNS解析出IP地址   if(hp)   memcpy(&hAddr,hp->h_addr_list,hp->h_length);   // IP地址   else{   return false;   }   }   HANDLE hIp=pIcmpCreateFile();   IP_OPTION_INFORMATION ipoi;   memset(&ipoi,0,sizeof(IP_OPTION_INFORMATION));   ipoi.Ttl =128;                  //Time-To-Live   unsigned char pSend[36];                               // 发送包   memset(pSend,'E',32);   int repSize=sizeof(ICMP_ECHO_REPLY)+32;   unsigned char pReply[100];                             // 接收包   ICMP_ECHO_REPLY* pEchoReply=(ICMP_ECHO_REPLY*)pReply;   DWORD nPackets=pIcmpSendEcho(hIp,hAddr,pSend,32,&ipoi,pReply,repSize,timeOut);    // 发送ICMP数据报文   if(pEchoReply->Status!=0)             // 超时,可能是主机禁用了ICMP 或者目标主机不存在  {   pIcmpCloseHandle(hIp);   return false;   }   pIcmpCloseHandle(hIp);   return true;
}
int main()
{InitIcmp();if (true == ICMPPing("127.0.0.1")){printf("OK.\n");}else{printf("NOT.\n");}system("pause");return 0;
}

方法二:

  • 使用原始套接字,模拟实现ping程序以进行网络连通检测,可跨平台,缺点是在linux下使用原始套接字必须拥有超级用户权限:
// 模拟实现ping程序,跨平台检测网络连接#ifdef _WIN32
#include <WinSock2.h>
#pragma comment(lib, "WS2_32")struct WindowsSocketLibInit
{WindowsSocketLibInit(){WSADATA wsaData;WORD sockVersion = MAKEWORD(2, 2);WSAStartup(sockVersion, &wsaData);}~WindowsSocketLibInit(){WSACleanup();}
} INITSOCKETGLOBALVARIABLE;
#else
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <ctime>
#include <cstdlib>
#include <cstdint>
#include <cstring>
#endif#include <string>
#include <limits>unsigned short getChecksum(unsigned short *buff, unsigned size);bool ping(std::string ip)
{static unsigned INDEX = 0;const unsigned IP_HEADER_LENGTH = 20;const unsigned FILL_LENGTH = 32;struct IcmpHdr{unsigned char icmpType;unsigned char icmpCode;unsigned short icmpChecksum;unsigned short icmpId;unsigned short icmpSequence;};int socketFd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);int timeoutTick = 200;setsockopt(socketFd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeoutTick, sizeof(timeoutTick));sockaddr_in des = {AF_INET, htons(0)};des.sin_addr.s_addr = inet_addr(ip.c_str());char buff[sizeof(IcmpHdr) + FILL_LENGTH] = {0};IcmpHdr *pIcmpHdr = (IcmpHdr *)(buff);unsigned short id = std::rand() % (std::numeric_limits<unsigned short>::max)();pIcmpHdr->icmpType = 8;std::cout << "---" << pIcmpHdr->icmpType << std::endl;pIcmpHdr->icmpCode = 0;pIcmpHdr->icmpId = id;pIcmpHdr->icmpSequence = INDEX++;std::memcpy(&buff[sizeof(IcmpHdr)], "TestTest", sizeof("TestTest"));pIcmpHdr->icmpChecksum = getChecksum((unsigned short *)buff, sizeof(buff));if (-1 == sendto(socketFd, buff, sizeof(buff), 0, (sockaddr *)&des, sizeof(des))){return false;}char recv[1 << 10];int ret = recvfrom(socketFd, recv, sizeof(recv), 0, NULL, NULL);if (-1 == ret || ret < IP_HEADER_LENGTH + sizeof(IcmpHdr)){return false;}IcmpHdr *pRecv = (IcmpHdr *)(recv + IP_HEADER_LENGTH);return !(pRecv->icmpType != 0 || pRecv->icmpId != id);
}unsigned short getChecksum(unsigned short *buff, unsigned size)
{unsigned long ret = 0;for (unsigned i = 0; i < size; i += sizeof(unsigned short)){ret += *buff++;}if (size & 1){ret += *(unsigned char *)buff;}ret = (ret >> 16) + (ret & 0xFFFF);ret += ret >> 16;return (unsigned short)~ret;
}

方法三:

  • 使用非阻塞connect函数和select定时相结合来检测网络连通,可跨平台,以下为windows下实现代码:
// 使用非阻塞connect和select定时检测解决connect失败时阻塞时间过长的问题#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")  int main()
{  // 网络初始化  WORD wVersionRequested;  WSADATA wsaData;  wVersionRequested = MAKEWORD(2, 2);  WSAStartup( wVersionRequested, &wsaData );  // 创建客户端socket(默认为是阻塞socket)  SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);  // 设置为非阻塞的socket  int iMode = 1;  ioctlsocket(sockClient, FIONBIO, (u_long FAR*)&iMode);   // 定义服务端  SOCKADDR_IN addrSrv;  addrSrv.sin_addr.S_un.S_addr = inet_addr("192.168.26.67");  addrSrv.sin_family = AF_INET;  addrSrv.sin_port = htons(31800);  // 超时时间  struct timeval tm;  tm.tv_sec  = 0;  tm.tv_usec = 5000;  int ret = -1;  // 尝试去连接服务端  if (-1 != connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)))  {  ret = 1; // 连接成功  }  else  {  fd_set set;  FD_ZERO(&set);  FD_SET(sockClient, &set);  if (select(-1, NULL, &set, NULL, &tm) <= 0)  {  ret = -1; // 有错误(select错误或者超时)  }  else  {  int error = -1;  int optLen = sizeof(int);  getsockopt(sockClient, SOL_SOCKET, SO_ERROR, (char*)&error, &optLen);   // 之所以下面的程序不写成三目运算符的形式, 是为了更直观, 便于注释  if (0 != error)  {  ret = -1; // 有错误  }  else  {  ret = 1;  // 无错误  }  }  }  // 设回为阻塞socket  iMode = 0;  ioctlsocket(sockClient, FIONBIO, (u_long FAR*)&iMode); //设置为阻塞模式  // connect状态  if (-1 == ret) {printf("error\n");} else if (1 == ret) {printf("success");}//printf("ret is %d\n", ret);  // 发送数据到服务端测试以下  if(1 == ret)  {  send(sockClient, "hello world", strlen("hello world") + 1, 0);  }  // 释放网络连接  closesocket(sockClient);  WSACleanup();  getchar();return 0;
}  

方法四:

  • 使用setsockopt函数设定socket连接、接收和发送的响应时间,可以通过connect之前设定SO_SNDTIMO来达到控制连接超时的目的:
// 自行添加相应头文件int main(int argc, char *argv[])
{int fd;struct sockaddr_in addr;struct timeval timeo = {3, 0};socklen_t len = sizeof(timeo);fd = socket(AF_INET, SOCK_STREAM, 0);  if (argc == 4)  timeo.tv_sec = atoi(argv[3]);  setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo, len);  addr.sin_family = AF_INET;  addr.sin_addr.s_addr = inet_addr(argv[1]);  addr.sin_port = htons(atoi(argv[2]));  if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {  if (errno == EINPROGRESS) {  fprintf(stderr, "timeout/n");  return -1;  }         perror("connect");  return 0;  }         printf("connected/n");  return 0;
}

方法五:

  • linux下直接调用执行ping子程序以实现检测网络连通功能:
// 自行添加相应代码文件int go_ping(char *svrip)
{int i = 0;while(i < 3){pid_t pid;if ((pid = vfork()) < 0) {printf("vfork error");exit(1);} else if (pid == 0) {if ( execlp("ping", "ping","-c 1",svrip, (char*)0) < 0){printf("execlp error\n");exit(1);}}int stat;waitpid(pid, &stat, 0);if (stat == 0){return 0;}sleep(3);i++;}return -1;
}

参考资料:

  • http://www.imooc.com/wenda/detail/443658
  • https://blog.csdn.net/qq_30650153/article/details/86244309
  • https://www.jianshu.com/p/95515d39897c
  • http://bbs.chinaunix.net/thread-2076080-1-1.html
  • https://blog.csdn.net/hj605635529/article/details/74157305

转载于:https://www.cnblogs.com/yiluyisha/p/10654552.html

实现网络连通检测的五种方法相关推荐

  1. 网络超时检测的三种方法

    网络超时检测的三种方法 作者:于老师,华清远见嵌入式学院讲师. 网络通信中,很多操作会使得进程阻塞,这时我们要设定时间,到时间后强制返回,避免进程在没有数据的情况下无限阻塞 这里我们总结一下网络超时检 ...

  2. 基于Halcon学习的缺陷检测【五】光伏电池片的指纹以及划痕检测【第二种方法】

     此例子主要是为了把光伏电池片的指纹以及划痕标注出来. 总代码:  *读取图片 read_image (Image, 'E:/研究生学习/电池片练习/手指印/截图.png')*清除窗口 dev_cle ...

  3. 弹性理论法研究桩基受力计算公式_收藏!桩基检测的7种方法

    来源:网络 版权归原作者所有,侵删 桩基检测,分为桩基施工前和施工后的检测:施工前,为设计提供依据的试验桩检测,主要确定单桩极限承载力:施工后,为验收提供提供依据的工程桩检测,主要进行单桩承载力和桩身 ...

  4. 五种方法创建 Java 对象,你知道几种呢?

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 来源 | 网络 五种方法创建java对象 作为Java开 ...

  5. 五种方法提高你的智力

    五种方法提高你的智力 智力是天生的,一成不变的吗?教你五种方法提高智力:1体验新鲜事物 2挑战自己3有创造力的思考4生活中,多玩"hard"模式5多与他人进行交流 弯兔123 20 ...

  6. 在生产环境下处理EFCore数据库迁移的五种方法

    在生产环境下处理EFCore数据库迁移的五种方法 原文链接:https://www.thereformedprogrammer.net/handling-entity-framework-core-d ...

  7. JavaScript 实现网页截屏五种方法

    JavaScript 实现网页截屏五种方法 最近研究了下如何利用JavaScript实现网页截屏,包括在浏览器运行的JS,以及在后台运行的nodeJs的方法.主要看了以下几个: PhantomJS P ...

  8. html转pdf(总结五种方法Java)

    html转pdf(总结五种方法Java) Java 实现html转pdf,总结五种方法. 推荐使用wkhtmltopdf,Itext 方法一:使用wkhtmltopdf 1.下载插件wkhtmltop ...

  9. 防止电子邮件网络钓鱼攻击的10种方法

    没有人愿意相信他们可能会成为网络钓鱼攻击的受害者.但是,网络钓鱼攻击正在不断增加,并且比以往更加复杂多变. 网络钓鱼攻击被认定为是公司和个人面临的最常见的安全威胁之一,这绝不是空穴来风,因为网络钓鱼攻 ...

最新文章

  1. 应用TP3.2.3的一些小问题(一)
  2. ITK:将所有像素的总和缩放为常数
  3. B站直播中HLS和去中心化P2P的实际应用
  4. vc++ List Control控件获得所有选中行的序号
  5. 即时通讯的企业应用和个人应用的区别
  6. ubuntu14.04-64位机配置android开发环境,ADT,sdk,eclipsea
  7. 为什么不能在lock语句的主体内使用#39;await#39;运算符?
  8. English trip EM2-PE 5B Presentation yourself favorite food Teacher:Ashley
  9. Atitit sql的执行功能 目录 1. 主要流程 1 1.1. 获取conn,执行sql取得结果, 1 1.2. Orm类的执行(hb mybatis为例 1 2. 常见sql执行框架与类库 1
  10. 数据结构-九宫格(回溯法)
  11. 【第60题】必学的枚举1-枚举的定义和基本特性
  12. 第一行代码 第三版 第11章网络技术 11.6.1 Retrofit 应用 报错:android.system.ErrnoException: isConnected failed: ECONNRE
  13. Permission denied(publickey) 解决办法
  14. Linux配置team
  15. 快递物流管理系统的设计与实现(SSM,MySQL)
  16. 百度一键Root使用教程
  17. 分享记录第一次在小鸟云网站备案
  18. H.266/VVC技术学习之环路滤波:去块滤波(Deblock)技术
  19. Vue中this.$confirm确定和取消执行不同的逻辑
  20. 用Servlet连接不上数据库

热门文章

  1. 非法侵入计算机系统的行为应,非法侵入计算机信息系统罪怎么定罪
  2. 哪一种开发语言有潜力有发展
  3. 【jq】如何优雅在shell脚本处理json?
  4. i黑马 | 一览群智胡健:先成为头牌,再造AI软件生态
  5. 18散列表(上):Word文档中的单词拼写检查功能是如何实现的
  6. 计算机中丢失comctl32.dll怎么办,win7无法启动程序因为计算机中丢失comctl32.dll怎么办...
  7. 【轻松电脑伴侣之神化世界】黑科技操作说明:微软的短板补充者--鼠标键盘全新升级+滚轮滚出来的精彩世界的真实体验
  8. 马原期末复习3. 经济基础和上层建筑之间的矛盾
  9. JAVA集合与字符串转换
  10. 计算机网络《组建对等网》实验报告指导书