Linux网络编程篇之ICMP协议分析及ping程序实现
Linux网络编程系列:
- Linux网络编程篇之Socket编程预备知识
- Linux网络编程篇之TCP协议分析及聊天室功能实现
如果对Linux网络编程,对socket通信不是太清楚的同学,强烈推荐看一下上述的预备知识,说不定,就会喜欢上Linux的网络编程世界
本系列会尽量对协议的部分进行介绍, 结合简单应用例子进行掌握学习.
ping程序功能实现
效果展示
在这里插入图片描述
ping.c程序代码
/** @Author: D-lyw * @Date: 2018-11-01 17:00:20 * @Last Modified by: D-lyw* @Last Modified time: 2018-12-01 17:01:42* @Description 在Linux环境利用socket编程,基于ICMP协议实现ping功能*/
#include "ping.h"
#include <stdio.h>
#include <string.h>
#include <netdb.h> // struct icpmhdr, struct iphdr , gethostbyname, hostent
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <netinet/ip_icmp.h>
#include <sys/time.h>char sendbuf[1024]; // 用来存放将要发送的ip数据包
struct sockaddr_in sockaddr, recvsock;
int sockaddr_len = sizeof(struct sockaddr);
struct hostent *host;
int sockfd;
int ping_time = 5;int main(int argc, char const *argv[])
{if(argc != 2){fprintf(stderr, "Usage: ping <remote_hostname>\n", argv[0]);exit(1);}int on = 1;int pid;int psend = 0, precv = 0;memset(&sockaddr, 0, sizeof(struct sockaddr));if((sockaddr.sin_addr.s_addr = inet_addr(argv[1])) == INADDR_NONE){// 说明输入的主机名不是点分十进制,采用域名方式解析if((host = gethostbyname(argv[1])) == NULL){fprintf(stderr, "ping %s , 未知的名称!\n", argv[1]);exit(1);}sockaddr.sin_addr = *(struct in_addr *)(host->h_addr);}sockaddr.sin_family = AF_INET;// 创建原始套接字 SOCK_RAW 协议类型 IPPROTO_ICMPif((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1){fprintf(stderr, "%s\n", strerror(errno));}setuid(getpid());pid = getpid();// 发包操作printf("PINGing %s %d data send.\n", argv[1], ICMP_DATA_LEN);int i = 1;int recvDataLen;int sendDatalen;char *recvbuf[1024];while(ping_time--){int packlen = packping(i++);if((sendDatalen = sendto(sockfd, sendbuf, packlen,0, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) < 0){fprintf(stderr, "send ping package %d error, %s\n", i, strerror(errno));continue ;}if((recvDataLen = recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr *)&recvsock, &sockaddr_len)) == -1){fprintf(stderr, "recvmsg error, %s\n", strerror(errno));continue;}decodepack(recvbuf, recvDataLen);sleep(1);}return 0;
}// 发送ping数据包
int packping(int sendsqe){struct icmp *icmp_hdr; // icmp头部指针icmp_hdr = (struct icmp *)sendbuf;icmp_hdr->icmp_type = ICMP_ECHO;icmp_hdr->icmp_code = 0;icmp_hdr->icmp_hun.ih_idseq.icd_id = getpid();icmp_hdr->icmp_hun.ih_idseq.icd_seq = sendsqe;memset(icmp_hdr->icmp_data, 0, ICMP_DATA_LEN);gettimeofday((struct timeval *)icmp_hdr->icmp_data, NULL);int icmp_total_len = 8 + ICMP_DATA_LEN;icmp_hdr->icmp_cksum = 0;icmp_hdr->icmp_cksum = checksum((unsigned char *)(sendbuf),icmp_total_len);return icmp_total_len;
}int decodepack(char *buf, int len){struct iphdr *ip_hdr;struct icmp *icmp_hdr;int iph_lenthg;float rtt; // 往返时间 struct timeval end; // 接收报文时的时间戳ip_hdr = (struct iphdr *)buf;// ip头部长度iph_lenthg = ip_hdr->ihl<<2;icmp_hdr = (struct icmp *)(buf + iph_lenthg);// icmp报文的长度len -= iph_lenthg;if(len < 8){fprintf(stderr, "Icmp package length less 8 bytes , error!\n");return -1;}// 确认是本机发出的icmp报文的响应if(icmp_hdr->icmp_type != ICMP_ECHOREPLY || icmp_hdr->icmp_hun.ih_idseq.icd_id != getpid()){fprintf(stderr, "Don't send to us!");return -1;}gettimeofday(&end, NULL);rtt = timesubtract((struct timeval *)&icmp_hdr->icmp_data, &end);printf("Received %d bytes from %s, ttl = %d, rtt = %f ms, icmpseq = %d \n", len, inet_ntoa(recvsock.sin_addr),ip_hdr->ttl, rtt, icmp_hdr->icmp_seq);return 0;
}// 计算时间差
float timesubtract(struct timeval *begin, struct timeval *end){int n;// 先计算两个时间点相差多少微秒n = ( end->tv_sec - begin->tv_sec ) * 1000000+ ( end->tv_usec - begin->tv_usec );// 转化为毫秒返回return (float) (n / 1000);
}// 校验和生成
ushort checksum(unsigned char *buf, int len){unsigned int sum=0;unsigned short *cbuf;cbuf=(unsigned short *)buf;while(len>1){sum+=*cbuf++;len-=2;}if(len)sum+=*(unsigned char *)cbuf;sum=(sum>>16)+(sum & 0xffff);sum+=(sum>>16);return ~sum;
}
ping.h程序代码
#include <netinet/ip_icmp.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <unistd.h>
#include <error.h>#define IPVERSION 4
#define ICMP_DATA_LEN 56int packping(int sendsqe);
ushort checksum(unsigned char *buf, int len);
int decodepack(char *buf, int len);
float timesubtract(struct timeval *begin, struct timeval *end);
Linux网络编程篇之ICMP协议分析及ping程序实现相关推荐
- linux tcp 服务器 c,Linux网络编程篇之Tcp协议介绍, C/S通信及聊天室实现
基于tcp协议的网络程序流程图如下: tcp协议网络程序流程图 服务器调用socket().bind().listen()完成初始化后,调用accept()阻塞等待,处于监听端口的状态 客户端调用so ...
- Linux网络编程:用C语言实现的聊天程序(同步通信)
通过TCP协议,用C语言实现的同步聊天程序,注释写的比较详细,个人觉得对字符串处理比较充分,能够正常编译运行,拿出来和大家分享一下! 1.客户端源代码: [cpp] view plaincopypri ...
- Linux网络编程-UDP和TCP协议详解
1|0一. 引言 网络协议是每个程序员都要掌握的基础知识,干啥都离不开网络,就算在家里新买了个路由器不是吗,同事连不上网,你的女朋友手机没有网看剧了正看到高潮部分,到那时候你打开百度......那嫌弃 ...
- Linux网络编程(传输层协议 )—tcp三次握手/四次挥手
传输层协议:负责应用程序之间数据传输-TCP/UDP UDP协议: 16位源端-对端端口:用于描述识别通信两端进程 16位数据报长度:能够存储最大数字 65535,(udp报文总大小不超过64k) 1 ...
- Linux网络编程基础
2019独角兽企业重金招聘Python工程师标准>>> (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍 客户端和服务端 网络程序和普通的程序有一个最大的 ...
- Linux网络编程 入门
Linux网络编程入门 (转载) (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍 客户端和服务端 网络程序和普通的程序有一个最大的区别是网络程序是由两个 ...
- Linux 网络编程 TCP
(一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍 客户端和服务端 网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客 ...
- Linux网络编程入门 (转载)
(一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍 客户端和服务端 网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客 ...
- Linux网络编程基础知识
Linux网络编程基础知识 1. 协议的概念 1.1 什么是协议 1.2 典型协议 2 网络应用程序设计模式 2.1 C/S模式 2.2 B/S模式 2.3 优缺点 3 分层模型 3.1 OSI七层模 ...
最新文章
- 2022-2028年中国醋酸行业投资分析及前景预测报告
- sql server分布式事务解决方案[新事务不能登记到指定的事务处理器中错误]
- Java并发编程71道面试题及答案
- 简单介绍ASP中Cache技术的应用
- 关于调试windows services的方法
- leader选举的原理
- mysql --max_allowed_packet=32m_mysql 设置max_allowed_packet 大小的办法
- 数据结构与算法之一快速排序
- SQLite第九课 sqlite3_set_authorizer案例
- POJ1276:Cash Machine(多重背包)
- 【OpenCV】 车牌识别检测
- 【单片机仿真】(五)寻址方式 — 立即寻址与寄存器间接寻址
- 服务器bmc口装系统,IBM X3650服务器BMC安装系统
- 中央气象台气象监测数据爬取Python实战分析
- 二十五、PHP内核探索:常量的实现 ☞ 脱离C语言和数学讨论底层都是耍流氓
- java从入门到弃坑十五天
- 自大型人格分析,如何改变自大型性格?
- MySQL数据库————MVCC
- 计算机连校园网没有弹出页面,我的电脑连接校园网 能连上,但是浏览器不弹出来 登录页面,为何...
- matlab:nargin,varargin,varargout