linux下简单的ping程序
来源:互联网 发布:未提交行1中的数据 编辑:程序博客网 时间:2024/06/15 21:33
简单的整理了一个以前用的ping程序, 个人觉得对初学者学习网络协议还是有一定帮助的,最好是利用抓包工具查看下具体的数据报文。
/* * ping.cpp * * Created on: Sep 10, 2014 * Author: xtank.nie@gmail.com */#include <sys/time.h>#include <netinet/ip_icmp.h>#include <sys/types.h>#include <unistd.h>#include <stdio.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include <string.h>#define SEND_PACKET_NUM (1)int calculate_checksum(unsigned short *packet, int length){ int num_left = length; int sum = 0; unsigned short *w = packet; unsigned short cksum = 0; while (num_left > 1) { sum += *w++; num_left -= 2; } if (num_left == 1) { /* 如果是奇数个字节,要在后面补上一个字节的0 */ *((unsigned char *)&cksum) = *((unsigned char *)w); sum += cksum; } sum = (sum>>16) + (sum & 0xffff); sum += (sum >> 16); cksum= ~sum; return cksum;}int crate_icmp_packet(char *packet_buf, uint32_t packet_no){ struct icmp *icmp_st; int data_size = 56; int packet_size; //head icmp_st = (struct icmp *)packet_buf; icmp_st->icmp_type = ICMP_ECHO; //请求回送 icmp_st->icmp_code = 0; icmp_st->icmp_cksum = 0; icmp_st->icmp_seq = packet_no; icmp_st->icmp_id = getpid(); //data gettimeofday((struct timeval *)icmp_st->icmp_data, NULL); packet_size = 8 + data_size; icmp_st->icmp_cksum = calculate_checksum((unsigned short *)packet_buf, packet_size); return packet_size;}int send_packet(int socket_fd, struct sockaddr *addr, char *packet_buf, int packet_no){ int packet_size; packet_size = crate_icmp_packet(packet_buf, packet_no); if ((packet_size = sendto(socket_fd, packet_buf, packet_size, 0, addr, sizeof(struct sockaddr_in))) == -1) { perror("sendto:"); return (-1); /* error */ } //printf("send pack size=%d\n", packet_size); return 0; /* success */}void calculate_interval(struct timeval *recv_time, struct timeval *send_time){ if ((recv_time->tv_usec -= send_time->tv_usec) < 0) { recv_time->tv_sec -= 1; recv_time->tv_usec += 1000000; } recv_time->tv_sec -= send_time->tv_sec;}int unpack(struct sockaddr_in *from, char *packet_buf, int packet_size, struct timeval *recv_time, double *rtt ,unsigned int *ttl){ struct ip *ip_st; struct icmp *icmp_st; int ipheader; ip_st = (struct ip *)packet_buf; ipheader = (ip_st->ip_hl << 2); icmp_st = (struct icmp *)(packet_buf + ipheader); packet_size -= ipheader; if (packet_size < 8) { printf( "recvfrom packet_size < 8!\n"); return (-1); /* error */ } if ((icmp_st->icmp_type == ICMP_ECHOREPLY) && (icmp_st->icmp_id == getpid())) { calculate_interval(recv_time, (struct timeval *)icmp_st->icmp_data);//收到的时间与发送的时间 *rtt = (recv_time->tv_sec * 1000) + (recv_time->tv_usec / 1000); *ttl = ip_st->ip_ttl; printf("%d byte from %s: icmp_seq = %u, ttl = %d, rtt = %.3fms\n", packet_size, inet_ntoa(from->sin_addr), icmp_st->icmp_seq, ip_st->ip_ttl, *rtt); return 0; } else { printf( "unpack error! icmp_type is %d, icmp_id is %d\r\n", (icmp_st->icmp_type == ICMP_ECHOREPLY), (icmp_st->icmp_id == getpid())); return -1; }}int recv_packet(int socket_fd, char *packet_buf, int *length, double *rtt, unsigned int *ttl){ int nbyte; struct sockaddr_in from_addr; struct timeval recv_time; socklen_t size = sizeof(struct sockaddr_in); if ((nbyte = recvfrom(socket_fd, packet_buf, *length, 0, (struct sockaddr *)&from_addr, &size)) == -1) { printf( "recvfrom return -1!\n" ); return (-1); } else { ;//printf("recv data len=%d\n", nbyte); } *length = nbyte; gettimeofday(&recv_time, NULL); if (unpack(&from_addr, packet_buf, nbyte, &recv_time, rtt, ttl) != 0) { return (-1); } return 0;}int ping(const char *addr){ unsigned long inaddr = 0; struct sockaddr_in dest_addr; struct hostent *host; int socket_ping = -1; int packet_size = 2048; char send_pac[2048] = {0}; char recv_pac[2048] = {0}; double iTimespend; unsigned int iTTL, send_packet_cnt = 0, recv_packet_cnt = 0;; memset(&dest_addr, 0x0, sizeof(struct sockaddr_in)); dest_addr.sin_family = AF_INET; if ((inaddr = inet_addr(addr)) == INADDR_NONE) { if ((host = gethostbyname(addr)) == NULL) { fprintf(stderr, "gethostbyname error.\n"); return -1; } memcpy((char *)&(dest_addr.sin_addr), host->h_addr, host->h_length); } else { dest_addr.sin_addr.s_addr = inaddr; } if((socket_ping = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1) { perror("socket:"); return -1; } printf("Ping %s(%s): %d bytes data in ICMP packets.\n", addr, inet_ntoa(dest_addr.sin_addr), 56); fd_set read_set; struct timeval timeout; int i = 1, ret; for (i = 1; i <=SEND_PACKET_NUM; i++) { if (send_packet(socket_ping, (struct sockaddr *)&dest_addr, send_pac, i) == -1) { printf("send_packet error\n"); close(socket_ping); return -1; } else { ++send_packet_cnt; } FD_ZERO(&read_set); FD_SET(socket_ping, &read_set); timeout.tv_sec = 1; timeout.tv_usec = 0; ret = select(socket_ping+1, &read_set, NULL, NULL, &timeout); if (ret > 0) { if (recv_packet(socket_ping, recv_pac, &packet_size, &iTimespend, &iTTL) == -1) { printf("recv_packet error\n"); } else { ++recv_packet_cnt; } } else if (ret == 0) { printf("Request time out.\n"); continue; } else { perror("select error."); continue; } } close(socket_ping); //statistics printf("---- (%s) ping statistics ----\n", addr); printf("%d packets transmitted, %d received, %d%% packet loss\n", send_packet_cnt, recv_packet_cnt, (int)(((send_packet_cnt-recv_packet_cnt) * 100)/send_packet_cnt)); return 0;}//quick testint main(int argc, char *argv[]){ if (argc != 2) { fprintf(stderr, "Usage: %s [address]\n", argv[0]); return 0; } return ping(argv[1]); }
结合抓包工具就比较容易理解:
执行:sudo ./ping 114.114.114.114
0 0
- linux下简单的ping程序
- linux下ping命令的简单应用
- Linux下禁止ping最简单的方法
- linux下最简单的禁ping方法
- C#做一个简单的Ping程序
- 如何写一个简单的ping程序
- linux下的简单的shell程序
- 简单的Linux下的socket程序
- linux下简单的流服务器程序
- 一个linux写的ping程序
- linux上Ping程序的实现
- linux c 更正版linux下c语言ping程序
- 参照ipconflict程序写的简单的ping 程序
- Linux ping简单实现
- Linux下ping命令的使用
- Linux下ping代码的错误
- linux下ping的C语言实现
- Linux下Ping的实现代码
- ACM Hrbeu OJ 1201 Simplest Task in Windows || ZOJ 2480
- VC(MFC)开发,控件界面开发,案例模板,V2.0正式发布,一例走天下
- android中的MotionEvent 及其它事件处理
- iOS开发之html解析
- OSI7层模型每层的作用
- linux下简单的ping程序
- linux内核 do_fork 函数源代码浅析
- dhhfdhddfh
- Seven-segment Display
- atitit.泛型编程总结最佳实践 vO99 java c++ c#.net php
- atitit.元编程总结 o99
- hdu 3535 AreYouBusy(经典分组背包)
- 程序员的人品问题:自我、情绪化与不善沟通
- atitit.避免NullPointerException 总结and 最佳实践 o99