Linux网络编程之原始套接字-ping协议实现

本文介绍了如何利用原始套接字在Linux下实现PING协议,详细阐述了PING协议的工作原理,并给出了实现细节,包括主机端和响应端的操作步骤。通过创建和填充ICMP首部和数据部分,发送并接收ICMP请求与响应包,计算响应时延。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.概述

PING协议是用来检验本地主机与远程主机是否连接,发送的是ICMP ECHO_REQUEST包。普通的套接字是基于TCP或者是UDP的,无法发送ICMP包,所以必须用原始套接字来实现。PING协议的客户端类型值为8,代码值为0,表示请求。而PING协议的响应端类型值为0,代码值也为0,表示应答. 以太网数据部分的最小值为46字节,而IP首部占20个字节,ICMP的首部占8个字节,所以PING的数据部分至少为4字节。

2.实现细节

主机端:

(1)创建原始套接字 socket(AF_INET,SOCK_RAW,htons(proto)),能够直接得到IP包

(2)填写ICMP首部和数据部分,即icmp_type(8),icmp_code(0)和icmp_data部分

(3)封装后发送ICMP请求包

响应端:

(1)创建原始套接字socket(AF_INET,SOCK_RAW,htons(proto))

(2)填写ICMP首部和数据部分,即icmp_type(0),icmp_code(0),icmp_data

(3)发送ICMP响应包

主机端收到ICMP响应包之后,即原始的IP包,将收到包的时间减去包的发送时间就可以得到响应时延。


3. PING协议的实现例子

#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <unistd.h>
#include <signal.h>
#include <arpa/inet.h>
#include <errno.h>
#include <sys/time.h>
#include <string.h>
#include <netdb.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
/**
通过原始套接字发送ICMP回显请求报文来实现ping协议
ICMP回显报文的结构
struct icmp{
  u_int8_t icmp_type;//消息类型
  u_int8_t icmp_code;//消息类型的子码
  u_int16_t icmp_cksum;//校验和
  union{
   struct ih_idseq{//显示数据报
     u_int16_t icd_id;//数据报所在进程的ID
     u_int16_6 icd_seq;//数据报序号

}ih_idseq;

}icmp_hun;

#define icmp_id icmp_hun.ih_idseq.icd_id
#define icmp_seq icmp_hun.ih_idseq.icd_seq
union{
 u_int8_t id_data[i];//数据
 

}icmp_dun;
#define icmp_data icmp_dun.id_data

}

**/
typedef struct pingm_packet{
    struct timeval tv_begin;//发送的时间
    struct timeval tv_end;//接收到响应包的时间
    short seq;//序号值
    int flag;//1表示已经发送但没有接收到回应包,0表示接收到响应包

}pingm_packet;
//保存已经发送包的状态值
static pingm_packet pingpacket[128];//定义一个包数组
static pingm_packet *icmp_findpacket(int seq);
static unsigned short icmp_cksum(unsigned char*data,int len);
static struct timeval icmp_tvsub(struct timeval end,struct timeval begin);
static void icmp_statistics(void);
static void icmp_pack(struct icmp*icmph,int seq,struct timeval *tv,int length);
static int icmp_unpack(char*buf,int len);
static void* icmp_recv(void*argv);
static void* icmp_send(void*argv);
static void icmp_sigint(int signo);
static void icmp_usage();
#define K 1024
#define BUFFERSIZE 512
static unsigned char send_buff[BUFFERSIZE];//定义发送缓冲区的大小
static unsigned char recv_buff[2*K];//定义接收缓冲区的大小,为防止接收端溢出,接收缓冲区稍微大一些
static struct sockaddr_in de
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值