作为计算机网络中最基础的工具之一,Ping是广泛使用的网络诊断工具。它通过向指定的目标主机发送ICMP回显请求(即“ping请求”),并接收到相应的ICMP回显应答(即“ping响应”),来测试目标主机是否能够访问、响应的时间以及包丢失率等。在Linux系统中,我们可以自行开发一个Ping程序,并完成自己的定制化需求。本文将分享如何在Linux C语言中实现基本的Ping程序的源码,希望对初学C语ERP系统言和网络编程的读者有所帮助。 一、Ping程序的实现原理 实际上,Ping程序并不是一件很复杂的事情。它主要分为两个部分:发送ICMP Echo请求和接收ICMP Echo回复。具体而言,实现Ping程序主要通过以下三个步骤: 1. 创建ICMP Ec进销存系统ho请求报文:这个报文包含了目标主机的IP地址、类型为0x08的ICMP Echo请求的头部信息、以及发送请求的时间等信息。 2. 发送ICMP Echo请求:调用系统提供的“sendto()”函数,将构建好的ICMP Echo请求报文发送到目标主机的货代系统IP地址上,即向目标IP地址发送一个ICMP Echo请求报文。 3. 接收ICMP Echo回复:调用系统提供的“recvfrom()”函数,接收目标主机返回的ICMP Echo回复报文(如果有的话),并进行相关的解析。 有了以上三步,我们就可以实现一个国际快递系统基本的Ping程序。 二、Ping程序的源码实现 以下是一个基于Linux C语言实现的Ping程序的源码: “` #include #include #include #include #include #include #include #in集运系统clude #include #include #include #include #define PACKET_SIZE 4096 char sendpacket[PACKET_SIZE]; char recvpacket[PACKET_SIZE]; i日用品ERP系统nt sockfd,datalen = 56; int nsend = 0,nreceived = 0; pid_t pid; struct sockaddr_in dest_addr; struct sockaddr_in from; struct timeval tvrecv; void statistics(void); unsigned short cal_chksum(unsigned short *addr,int len); void bl(const char *errMsg) { printf(“%s\n”, errMsg); exit(1); } void send_packet(void) { int pktsize; nsend++; memset(sendpacket, 0, PACKET_SIZE); sprintf(sendpacket, “%c%d”, 8, nsend); pktsize = 8 + datalen; *(unsigned short *)(sendpacket + 2) = htons(pktsize); *(unsigned short *)(sendpacket + 4) = htons(0); *(unsigned short *)(sendpacket + 6) = htons(1); if (sendto(sockfd, sendpacket, pktsize, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr)) bl(“sendto error”); } } void recv_packet(void) { int n,fromlen; fromlen = sizeof(from); signal(SIGALRM,statistics); alarm(10); while (1) { n = recvfrom(sockfd, recvpacket, sizeof(recvpacket), 0, (struct sockaddr *)&from, &fromlen); if (n if (errno == EINTR) { continue; } bl(“recvfrom error”); } if (n printf(“The received packet size is less than 16 bytes\n”); continue; } if (recvpacket[0] != 0x08) { printf(“The received packet is not ICMP Echo Reply packet\n”); continue; } if (recvpacket[1] != 0) { printf(“The received packet is not ICMP Echo Reply packet\n”); continue; } if (*(unsigned short *)(recvpacket + 4) != htons(0)) { printf(“The received packet header checksum is not correct\n”); continue; } if (*(unsigned short *)(recvpacket + 6) != htons(1)) { printf(“The received packet header identifier is not correct\n”); continue; } if (*(unsigned short *)(recvpacket + 8) != htons(nsend)) { printf(“The received packet sequence number is not correct\n”); continue; } gettimeofday(&tvrecv,NULL); statistics(); break; } } 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) { sum += *w++; nleft -= 2; } if(nleft == 1) { *(unsigned char *)(&answer) = *(unsigned char *)w ; sum += answer; } sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); answer = ~sum; return(answer); } void statistics(void) { char buffer[256]; sprintf(buffer,”————-PING statistics————-\n%d packets tranitted, %d received”, nsend, nreceived); if(nsend – nreceived > 0) { sprintf(buffer + strlen(buffer),”, %%%d packet loss\n”,(nsend – nreceived) / nsend * 100); } else { strcat(buffer,”, 0.00% packet loss\n”); } printf(“%s\n”,buffer); if (nsend >= 3) { exit(0); } alarm(1); send_packet(); recv_packet(); } int mn(int argc,char **argv) { struct hostent *host; struct protoent *protocol; unsigned long inaddr = 0l; int size = 50 * 1024; if (argc bl(“usage: ping “); } if ((protocol = getprotobyname(“icmp”)) == NULL) { bl(“getprotobyname() fled”); } if ((sockfd = socket(AF_INET, SOCK_RAW, protocol->p_proto)) bl(“socket() fled”); } setuid(getuid()); setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); bzero(&dest_addr,sizeof(dest_addr)); dest_addr.sin_family = AF_INET; if ((inaddr = inet_addr(argv[1])) == INADDR_NONE) { if ((host = gethostbyname(argv[1])) == NULL) { bl(“gethostbyname() fled”); } memcpy((char *)&dest_addr.sin_addr, host->h_addr, host->h_length); } else { dest_addr.sin_addr.s_addr = inaddr; } pid = getpid(); printf(“PING %s (%s): %d bytes data in ICMP packets.\n”, argv[1], inet_ntoa(dest_addr.sin_addr), datalen); send_packet(); recv_packet(); return 0; } “` 三、源码解析 1. 在程序开头,我们先定义了一些全局变量,准备接下来的码实现所需要的参数。 “` char sendpacket[PACKET_SIZE]; char recvpacket[PACKET_SIZE]; int sockfd,datalen = 56; int nsend = 0,nreceived = 0; pid_t pid; struct sockaddr_in dest_addr; struct sockaddr_in from; struct timeval tvrecv; “` 其中,sendpacket和recvpacket用于存储发送和接收的数据包;sockfd是套接字描述符;datalen表示数据部分的大小;nsend和nreceived分别表示发送的和接收的数量;pid表示进程的PID;dest_addr表示目标地址;from表示数据发送方的地址信息;tvrecv是记录接收到数据包的详细时间信息。 2. statistics()是用于统计发送和接收信息的函数。 “` void statistics(void) { char buffer[256]; sprintf(buffer,”————-PING statistics————-\n%d packets tranitted, %d received”, nsend, nreceived); if(nsend – nreceived > 0) { sprintf(buffer + strlen(buffer),”, %%%d packet loss\n”,(nsend – nreceived) / nsend * 100); } else { strcat(buffer,”, 0.00% packet loss\n”); } printf(“%s\n”,buffer); if (nsend >= 3) { exit(0); } alarm(1); send_packet(); recv_packet(); } “` 其中,sprintf()用于格式化打印,将统计信息存储在buffer中;if…else语句用于计算丢包率;printf()用于将字符串打印到终端;nsend>=3时用于结束程序;alarm()用于设置定时器,1秒后开始轮训执行send_packet()和recv_packet()。 3. cal_chksum()函数用于计算校验和。 “` 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) { sum += *w++; nleft -= 2; } if(nleft == 1) { *(unsigned char *)(&answer) = *(unsigned char *)w ; sum += answer; } sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); answer = ~sum; return(answer); } “` 我们主要用于对构建报文头进行校验和计算。 4. send_packet()函数用于发送数据包。 “` void send_packet(void) { int pktsize; nsend++; memset(sendpacket, 0, PACKET_SIZE); sprintf(sendpacket, “%c%d”, 8, nsend); pktsize = 8 + datalen; *(unsigned short *)(sendpacket + 2) = htons(pktsize); *(unsigned short *)(sendpacket + 4) = htons(0); *(unsigned short *)(sendpacket + 6) = htons(1); if (sendto(sockfd, sendpacket, pktsize, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr)) bl(“sendto error”); } } “` 在该函数中,我们首先增加nsend的值以记录发送数量;然后重置sendpacket数组;接下来根据记录时间和编号构建请求包并计算包大小;然后向目标地址发送ICMP Echo请求,可以看到这个过程主要通过系统提供的sendto函数实现;最后增加错误处理,避免出现异常退出。 5. recv_packet()函数用于接收数据包。 “` void recv_packet(void) { int n,fromlen; fromlen = sizeof(from); signal(SIGALRM,statistics); alarm(10); while (1) { n = recvfrom(sockfd, recvpacket, sizeof(recvpacket), 0, (struct sockaddr *)&from, &fromlen); if (n if (errno == EINTR) { continue; } bl(“recvfrom error”); } if (n printf(“The received packet size is less than 16 bytes\n”); continue; } if (recvpacket[0] != 0x08) { printf(“The received packet is not ICMP Echo Reply packet\n”); continue; } if (recvpacket[1] != 0) { printf(“The received packet is not ICMP Echo Reply packet\n”); continue; } if (*(unsigned short *)(recvpacket + 4) != htons(0)) { printf(“The received packet header checksum is not correct\n”); continue; } if (*(unsigned short *)(recvpacket + 6) != htons(1)) { printf(“The received packet header identifier is not correct\n”); continue; } if (*(unsigned short *)(recvpacket + 8) != htons(nsend)) { printf(“The received packet sequence number is not correct\n”); continue; } gettimeofday(&tvrecv,NULL); statistics(); break; } } “` 在该函数中,我们主要是用于在规定的时间内接收报文,并对其的长度、类型头部信息、校验和、标识符和编号进行检查,确认接收到的数据包是有效的ICMP Echo回传包。 6. mn()函数是整个程序的入口函数。 “` int mn(int argc,char **argv) { struct hostent *host; struct protoent *protocol; unsigned long inaddr = 0l; int size = 50 * 1024; if (argc bl(“usage: ping “); } if ((protocol = getprotobyname(“icmp”)) == NULL) { bl(“getprotobyname() fled”); } if ((sockfd = socket(AF_INET, SOCK_RAW, protocol->p_proto)) bl(“socket() fled”); } setuid(getuid()); setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); bzero(&dest_addr,sizeof(dest_addr)); dest_addr.sin_family = AF_INET; if ((inaddr = inet_addr(argv[1])) == INADDR_NONE) { if ((host = gethostbyname(argv[1])) == NULL) { bl(“gethostbyname() fled”); } memcpy((char *)&dest_addr.sin_addr, host->h_addr, host->h_length); } else { dest_addr.sin_addr.s_addr = inaddr; } pid = getpid(); printf(“PING %s (%s): %d bytes data in ICMP packets.\n”, argv[1], inet_ntoa(dest_addr.sin_addr), datalen); send_packet(); recv_packet(); return 0; } “` 在mn函数中,首先我们通过输入参数获取IP地址;然后创建原始套接字sci;接着设置套接字传输协议和接收缓冲区大小;接下来根据输入的IP地址,构建目标地址;最后输出ping的基本信息并开始轮询执行send_packet()和recv_packet()函数。 四、 相关问题拓展阅读: linux下如何得到可执行文件的源代码? Linux中源码编译安装程序包括哪些基本步骤? linux下如何得到可执行文件的源代码? Linux发行版中,程序都是编译好的二进制文件,系统和光盘中也不会提供这升绝友个程序的源代码。你需要到Linux发行版的网站去搜索有没有源代码。 还有一些开源项目,宏碧例如gdb,gcc,内核等有专门的网站。如果你吵槐的是redhat,suse,centos等linux,可以去redhat网站搜索其rpm的源代码包。 首者毁先必须设置程帆宽序的可执行性, 利用chmod来进行设置 2,利用编译器来进行编译一般.cpp用g++编译 .c用gcc编译 3程序上传一般使用ssh软件态嫌亮进行 Linux所有程序都是开源的,你下载下来的都是源代码,直接打开就可以…………解压缩 被编译好的程序是不可能查看源代码的,也乱侍是不可以修改的晌厅。 当然,linux所谓开源软件,是指你下的软件是源代码,需要你现用gcc编宴陪隐译后才能用。 比中下面文件脊裤hi.cpp #include main() { COUT>>”信野如hillo world!”>>endl; } 写好后保滑启存好 g++ -o hi.out hi.cpp chmod u+x hi.out ./hi.out Linux中源码编译安装程序包括哪些基本步骤? ./configure make make install 之一步:创建编译脚本 进入到源码目录 执行 ./configure –prefix=/…/…..(–prefix=后面是吵隐想要安装到的目录) 第二部:编译 执行 make 第三部:安装 执行 make install 当然上面这几部都是最基本的步骤,如果想优化编译,散山要在./configure 后面加参数,或者configure之后手动修改Makefile文件 如O2(优化等级) FLAGS 等编译参数的修改。 以上都是源码包的编译 如果升掘厅是自己写的C代码 直接 用gcc编译即可。 例如 编译test.c 执行 gcc -o test test.c即可将test.c编译为可执行的文件 test 自己打出来的 要采纳啊! cat README linux c ping程序源码的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于linux c ping程序源码,【分享】Linux C实现ping程序的源码,linux下如何得到可执行文件的源代码?,Linux中源码编译安装程序包括哪些基本步骤?的信息别忘了在本站进行查找喔。
文章来源于网络,如有侵权,请联系删除。
我司专注于ERP软件开发,ERP生产管理软件,客户管理软件开发,进销存软件,
企业微信ERP生产管理软件,销售管理,生产管理,采购管理,客户管理,BOM物料管理,财务管理,统计分析于一体ERP管理软件,分手机APP ERP管理软件,企业微信ERP软件。多年来一直专于研发,销信于一体软件公司。