用C 语言实现 Ping

来源:互联网 发布:java 搜索算法 编辑:程序博客网 时间:2024/05/21 12:41

一.套接字

 int socket(int domain,int type,int protocol); 参数domain确定通信特性,它有4个域分别为  AF_INET     IPV4英特网域  AF_INET6    IPV6因特网域  AF_UNIX     UNIX 域  AF_UPSPEC   未指定 参数 type 确定套接字类型,进一步确定通信特性  SOCK_DGRAW  固定长度、无连接、不可靠的包文传递  SOCK_RAW    IP 协议数据接口  SOCK_SEQPACKET 固定长度的、有序的、可靠的、面向连接的报文传递  SOCK_STREAM 有序的、可靠、双向的、面向连接的字节流 参数 protocol 通常是0,表示为给定的域和套接字选择默认 协议。AF_INT域SOCK_STREAM默认为传输控制协议 TCP, AF_INT域套接字类型 SOCK_DGRAM 的默认协议是 UDP。 下面为英特网套接字定义的协议: IPPROTO_IP,     IPPROTO_IPV6,   IPPROTO_ICMP IPPROTO_RAW,    IPPROTO_TCP,    IPPROTO_UDP 返回值为套接字描述符,本质为一个文化描述符

SOCK_RAW和IPPROTO_ICMP

SOCK_RAW套接字提供一个数据报接口,用于直接访问下面的网络层因为其绕过了传输协议(如 TCP和 UDP),所以我们必须自己构造协议头部。注意当我们创建这个套接字的时候我们必须有超级用户特权。因此实现 Ping 我们先来定义 ICMP 头部 struct ICMPHEAD{       u_int8_t type;       u_int8_t code;       u_int16_t checkSum;       u_int16_t id;       u_int16_t seq;};我们实现 Ping 必须发送回显请求数据包,其类型代码为8,代码报文为0.回显请求数据包类型为0,代码报文为0.id 给数据包一个标示用于判断是否为我们所发送的数据包。checkSum为检验和字段,包括数据在内的整个 ICMP 报文检验和。ushort GenerationChecksum(ushort*pBuf,int iSize){unsigned long cksum = 0;while(iSize > 1){    cksum+=*pBuf++;    iSize-=sizeof(ushort);}if(iSize) cksum+=*pBuf++;cksum = (cksum>>16)+(cksum&0xffff);cksum += (cksum>>16);return (ushort)(~cksum);}定义完我们的数据包之后,剩下就是定义一个目的地址。struct sockaddr_in {__uint8_t   sin_len;sa_family_t sin_family;in_port_t   sin_port;struct  in_addr sin_addr;char        sin_zero[8];};sin_family为地址族sin_addr为目的地址sin_port为端口号struct sockaddr_in destSocketAddr;destSocketAddr.sin_family = AF_INET;destSocketAddr.sin_addr.s_addr = ulDestIP;destSocketAddr.sin_port = htons(0);memset(destSocketAddr.sin_zero, 0, sizeof(destSocketAddr.sin_zero));

发送ICMP

ssize_t sendto(int, const void *, size_t,int, const struct sockaddr *, socklen_t)第一个参数为套接字描述符。第二个参数为 ICMP 数据包第三个参数为 ICMP 的大小第四个参数为目的地址,为使不同的地址格式传入这个函数,因此必须强转为 sockaddr。第五个参数为目的地址大小

接受回显应答报文

ssize_t recvfrom(int, void *, size_t, int,struct sockaddr * __restrict,socklen_t * __restrict)第一个参数为套接字描述符第二个参数接受数据缓存区的首地址第三个参数为数据缓存区大小第四个参数为接受发送数据的地址信息第五个参数为第四个参数的大小接受的数据为 IP 数据报,因此我们可以定义一个结构体来方便我们操作 IP 数据报ip 头结构体typedef struct tag_iphdr        {    u_int8_t   iphVerLen;//注意这个包括版本和首部长度    u_int8_t   ipTOS;    ushort  ipLength;    ushort  ipID;    ushort  ipFlags;    u_int8_t   ipTTL;    u_int8_t   ipProtacol;    ushort  ipChecksum;    int   ipSource;    int   ipDestination;} IPHDR;利用 ip 头部中的首部长度信息获得我们需要的回显应答数据包。解析回显应答数据包我们的 Ping就完成了。

DEMO在这里

0 0