ping命令的C语言实现(linux, IPv4,简单版)
这个程序主要运用了ICMPv4协议(回显请求)来测试本机到某服务器的网络是否连通,因为其中用到了原始套接字,所以运行该程序需要管理员权限。PS:本程序只支持一种输入方式:./myping <hostname>,不支持其他参数。思路:1:根据hostname参数创建原始套接字。2:每隔1秒钟向服务器发送一个ICMP回显请求。3:循环接收从服务器返回的应答并处理其数据。上代码:[cpp]#include <signal.h>#include <stdio.h>#include <errno.h>#include <stdlib.h>#include <netinet/in_systm.h>#include <netinet/ip.h>#include <netinet/ip_icmp.h>#include <arpa/inet.h>#include <netdb.h>#include <sys/un.h>//各种缓冲区的长度#define BUFSIZE 1500//ICMP回显请求的长度#define DATA_LEN 56struct proto{struct sockaddr *sasend; /* sockaddr{} for send, from getaddrinfo */struct sockaddr *sarecv; /* sockaddr{} for receiving */socklen_t salen; /* length of sockaddr{}s */int icmpproto; /* IPPROTO_xxx value for ICMP */};//全局变量pid_t g_pid;int g_sockfd;struct proto g_proto = { NULL, NULL, 0, IPPROTO_ICMP };//处理服务器返回的ICMP回显信息void proc_msg(char *, ssize_t, struct msghdr *, struct timeval *);//发送ICMP回显请求void send_msg(void);//循环发送、接收信息void readloop(void);//定时器入门函数,每隔一秒一次发送ICMP请求void sig_alrm(int);//计算两个时间之间的间隔void tv_sub(struct timeval *, struct timeval *);//获取服务器的地址等信息struct addrinfo *host_serv(const char *host,const char *serv, int family, int socktype);//根据服务器信息,得到服务器的IP地址char *sock_ntop_host(const struct sockaddr *sa, socklen_t salen);//计算校验和uint16_t in_cksum(uint16_t *addr, int len);//输出错误信息,退出程序void error_quit(const char *str);int main(int argc, char **argv){int c;struct addrinfo *ai;struct sockaddr_in *sin;char *ip_address;char *host;//本程序只支持一种输入方式:./myping <hostname>if( argc != 2 )error_quit("usage: myping <hostname>");host = argv[1];//将pid的高二位全置为0,ICMP的ID只有16位g_pid = getpid() & 0xffff;//设置定时器,每秒钟向服务器发送一次请求signal(SIGALRM, sig_alrm);//获取服务器的信息(addrinfo结构)ai = host_serv(host, NULL, 0, 0);ip_address = sock_ntop_host(ai->ai_addr, ai->ai_addrlen);printf("PING %s (%s): %d data bytes\n",ai->ai_canonname ? ai->ai_canonname : ip_address,ip_address, DATA_LEN);//如果返回的协议簇不是AF_INET(IPv4),则退出if ( ai->ai_family != AF_INET )error_quit("unknown address family");//设置proto结构体g_proto.sasend = ai->ai_addr;g_proto.sarecv = calloc(1, ai->ai_addrlen);g_proto.salen = ai->ai_addrlen;//开始循环发送/接收请求readloop();return 0;}void readloop(void){int size;char recvbuf[BUFSIZE];char controlbuf[BUFSIZE];struct msghdr msg;struct iovec iov;ssize_t n;struct timeval tval;//创建一个IPv4的原始套接字g_sockfd = socket(g_proto.sasend->sa_family, SOCK_RAW, g_proto.icmpproto);if( -1 == g_sockfd )error_quit("socket error");//放弃管理员权限//这个程序中,只用创建原始套接字时需要管理员权限setuid(getuid());//设置socket的接收缓冲区size = 60 * 1024;setsockopt(g_sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));//发出第一个请求sig_alrm(SIGALRM);//为recvmsg调用设置msghdr结构iov.iov_base = recvbuf;iov.iov_len = sizeof(recvbuf);msg.msg_name = g_proto.sarecv;msg.msg_iov = &iov;msg.msg_iovlen = 1;msg.msg_control = controlbuf;//开始死循环,不断读取和处理从服务器中返回的信息while( 1 ){msg.msg_namelen = g_proto.salen;msg.msg_controllen = sizeof(controlbuf);n = recvmsg(g_sockfd, &msg, 0);if (n < 0){if (errno == EINTR)continue;elseerror_quit("recvmsg error");} &nbs补充:软件开发 , C语言 ,
上一个:关于C语言中对数组取址的问题
下一个:用c语言写的读一行源代码
- 更多C/C++疑问解答:
- 关于c++的cout输出的问题。
- 在学校里学过C和C++,不过学的很一般,现在自学C#,会不会很难?
- 全国计算机二级C语言笔试题
- 已知某树有2个2度结点,3个3度结点,4个4度结点,问有几个叶子结点?
- c++数据结构内部排序问题,整数排序
- 2012九月计算机二级C语言全国题库,,急求急求
- 如果assert只有一个字符串作为参数,是什么意思呢?
- C语言中,哪些运算符具有左结合性,哪些具有右结合性,帮忙总结下,谢谢了!
- 为什么用结构体编写的程序输入是,0输不出来啊~~~
- 将IEEE—754的十六进制转化为十进制浮点类型,用C或C++都行,多谢各位大侠啊,非常感谢!
- 为什么这个程序求不出公式?
- 这个链表倒置的算法请大家分析下
- c语言函数库调用
- C语言unsigned int纠错
- C语言快排求解啊