数据通信实验
一、 实验名称及内容
名称:利用 Winsock 完成类似于系统自带的 ping 远程主机的功能
内容:利用 Winsock 完成基于 ICMP 协议的 ping 程序,该程序完成类似于系统自带的 ping 远程主机的功能,可以直接 ping IP 地址,也可以自动进行域名解析,并且可以指定 ping 次数和统计 ping 结果,基本包含了系统自带的 ping 命令的基本功能。并且,若一台远程主机有多个 IP,则该程序会自动依次 ping 该主机所有 IP。用户可以通过该程序 ping 远程主机来测试连接性。
二、实验过程和结果
环境
物理主机系统:macOS Catalina 10.15.4
虚拟机系统:Windows 10 专业版 x64
计算机名:691B
虚拟机软件:Parallels Desktop 15 for Mac Pro Edition, version 15.1.4 (47270)
编程环境(IDE):Visual Studio 2019
程序设计
- 域名解析(获取远程主机名)
- 调用 WSAStartup() 函数,初始化 winsock
- 调用 getaddrinfo() 函数,获得指定 IP 或域名的主机信息,完成域名解析
- ping 远程主机,循环指定次数,默认 4 4 4 次
- 调用 WSAStartup() 函数,初始化 winsock
- 调用 socket() 函数创建一个 Socket (PF_INET, SOCK_RAW, IPPROTO_ICMP)
- 调用 setsockopt() 设置接收超时(1s)
- 设置目的地址
- 构造 ICMP 封包
- 构造 ICMP 报头
- 在报头后填充数据,可以任意
- 计算校验和
- 调用 sendto() 函数发送 ICMP 报文
- 调用 recvfrom() 函数接收 ICMP 报文
- 统计 ping 信息
程序流程图
程序使用
编译后在命令行运行可执行程序:
myping.exe [IP/DN] ([times](default 4 times))
如:
myping.exe baidu.com
myping.exe baidu.com 10
myping.exe 39.156.69.79 10
程序主体说明
数据结构
#include <stdio.h>
#include <time.h>
#include <Winsock2.h>
#include <ws2tcpip.h>
#include <Windows.h>
#include <sstream>
#include <iostream>
#include <string>
using namespace std;
#pragma comment (lib, "ws2_32.lib")
// 2字节 对齐 sizeof(icmp_header) == 8
// 这是ping 在wireshark抓包中的数据结构
typedef struct icmp_header // ICMP报头
{
unsigned char icmp_type; // 消息类型
unsigned char icmp_code; // 代码
unsigned short icmp_checksum; // 校验和
unsigned short icmp_id; // 用来惟一标识此请求的ID号,通常设置为进程ID
unsigned short icmp_sequence; // 序列号
} icmp_header;
函数
u_short ss2n(string s) // 将字符串转为数字,用来将argv指向的字符串类型的指定ping次数转为短整型
{
stringstream ss;
u_short u;
ss << s;
ss >> u;
return u;
}
// 计算校验和
unsigned short chsum(struct icmp_header* picmp, int len)
{
long sum = 0;
unsigned short* pusicmp = (unsigned short*)picmp;
while (len > 1)
{
sum += *(pusicmp++);
if (sum & 0x80000000)
sum = (sum & 0xffff) + (sum >> 16);
len -= 2;
}
if (len)
sum += (unsigned short)*(unsigned