Ping程序设计
计算机科学与技术学院课程设计成绩单优秀:90分~100分良好:80分~89分中等:70~79分及格:60~69分不及格0分~59分武汉科技大学计算机科学与技术学院制表计算机科学与技术学院课程设计报告课程名称:计算机网络专业:软件工程班级: 09 级 01 班学号: ************ *名:**指导老师:**基于Socket的PING程序设计ping命令是使用频率极高的一个网络测试命令,用以测试从一个主机到另一个主机间的网络上否可达。
windows自带的ping命令具有强大的功能,它有很多选项用于实现不同的测试目的。
本章模仿windows的ping命令,用c语言实现了一个简单的命令。
本章着重讲述ping命令的实现原理和c语言的网络编程方法。
读者可以在本章的基础上,对本章实现的ping命令进行扩展,开发出功能更强大、更完善的ping命令,并进一步掌握网络编程的方法。
1、设计目的本章通过设计Ping程序,讲解Ping程序的实现原理,并初步讲解了c语言网络编程技术。
本章涉及很多网络编程函数和编程技巧。
包括库文件的导入;winsock的初始化、注销;socket的创建、关闭;设置socket选项;根据主机名获取IP地址;从堆中分配一定数量的空间、释放从堆中分配的空间;获取当前进程ID号;数据报的发送;数据报的接等。
通过本程序的训练,使读者对网络编程有一定的了解,掌握Ping程序的设计方法,掌握网络编程的方法和技巧,从而编写出功能更强大的程序。
2、功能描述本章用c语言实现的ping命令,能用于测试一个主机到另一个主机间的联通情况,程序还提供了几个选项以实现不同的功能。
(1)实现ping功能。
程序能实现基本的ping操作,发送ICMP回显请求报文,接收应答报文。
(2)能记录路由。
程序提供了“-r”选项,用以记录从源主机到目的主机的路由。
(3)能输出指定条数的记录。
程序提供了“-n”选项,用以输出指定条数的记录。
(4)能按照指定大小输出每条记录。
程序提供了“datasize”选项,用以指定输出的数据报的大小。
(5)能输出用户帮助。
程序提供了用户帮助,显示程序提供的选项以及选项格式等。
3、总体设计3.1、功能模块设计3.1.1、功能模块图本系统共有 4 个模块,分别是初始化模块、功能控制模块、数据控制模块、数据报解读模块和ping测试模块,如图9.1所示。
各模块功能描述如下。
系统模块图(1) 初始化模块。
该模块用于初始化各个全局变量,为全局变量赋初始值;初始化,加载库。
(2)功能控制模块。
该模块是被其它模块调用,其功能包括获取参数、计算校验和填充数据报文、释放占用资源和显示用户帮助。
(3)数据报解读模块。
该模块用于解读接收到的报文和选项。
(4)测试模块。
该模块是本程序的核心模块,调用其他模块实现其功能,主要是实现的功能。
3.1.2、系统流程图系统执行的流程图9.2所示。
程序首先调用IniPing()函数初始化各全局变量,然后GetArgments()函数获取用户输入的参数,检查用户输入的参数,如果参数不正确或者没有输入参数,则显示用户帮助信息(User help ),并结束程序;如果参数正确,则对指定目的地执行Ping命令,如果Ping通,则显示Ping结果并释放占用资源,如果没有Ping通,则报告错误信息,并释放占用资源。
图9.2 系统流程图3.1.3、参数获取(GetArgments()函数)流程图获取的参数包括“-r”(记录路由)、“-n”(记录条数程序,任意的整数)和datasize(数据报大小)。
程序首先判断每一个参数的第一字符,如果第一个字符是“-”(短横线),则认为是“-r”或者“-n”中的一个,然后作进一步判断。
如果该参数的第二个字符是数字,则判断该参数为记录的条数,如果该参数的第二个字符是“r”,则判断该参数为“-r”,用于记录路由;如果参数的第一个字符是数字,则认为参数是IP地址;或者datasize,然后作进一步的判断。
如果该参数中不存在非数字的字符,则判断该参数为datasize;如果存在非数字的字符,则判断该参数为IP地址;其他情况则判断为主机名。
参数获取的流程如图9.3所示。
图9.3 参数获取流程图3.1.4、ping()函数流程图ping()函数是本程序的核心部分它调用其他模块的函数来实现,其主要步骤包括创建接字,设置路由选项(如果需要的话)、设置接收和发送超时值、名字解析(如果需要的话)、分配内存、创建ICMP 报文、发送ICMP请求报文、接收ICMP应答报文和解读ICMP报文。
其执行流程如图9.4所示。
图9.4 Ping 函数流程图3. 2、数据结构设计本程序定义了3个结构体:-iphdr、-icmphdr、和-ipotionhdr,分别用于存放IP报头信息、ICM P报头信息和IP路由选项信息。
3.2.1、定义IP报头结构体Typedef struct _iphdr{Unsigned int h_len:4;Unsigned int version:4;Unsigned char tos;Unsigned short total_len;Unsigned short ident;Unsigned short frag_flags;Unsigned char ttl;Unsigned chor proto;Unsigned short checksum;Unsigned int sourceIP;Unsigned int destIP;} IpHeader;其中各字段表示意义如下。
h-len:4 : 表示IP报头长度,首部长度指的是首部占32bit字的数目,包括任何选项。
由于它是一个4bit 字段,因此首部最长为60个字节,不包括任何选项的IP报头是20个字节。
version:4: 表示IP的版本号,这里表示Ipv4.。
top: 表示服务的类型,可以表示最小时延,最大吞吐量,最高可靠性和最小费用。
total –len: 整个IP数据报的总长度。
ident: 唯一的标识符,标识主机发送的每一份数据报。
frag-flags: 分段标志,表示过长的数据报是否要分段。
ttl: 生存期,表示数据报可以经过的最多路由器数。
proto: 协议类型(TCP、UDP等)。
checksum: 校验和。
sourceIP: 源IP地址。
destIP: 目的IP地址。
3.2.2、定义ICMP报头结构体Typedef struct –icmphdr{BYTE i_type;BYTE i_code :USHORT i_cksum;USHORT i_id;USHORT i_seq;ULONG timestamp;} IcmpHeader;其中各字段表示意义如下。
i_type : ICMP报文类型。
i_code : 该类型中的代码号,一种ICMP 报文的类型号和该类型中的代码号共同决定。
、i_cksum: 校验和。
i_seq: 序列号,序列号从0开始,每发送一次新的回显请求就加1.timestamp: 时间戳。
3.2.3、定义IP 选项结构体Typedef struct _ipoptionhdr{Unsigned char code;Unsigned char len;Unsigned char ptr;Unsigned loang addr[9];} IpOptionHeader;其中各字段表示意义如下。
Code: 指明IP 选项类型,对于路由记录选项,它的值是7。
Len: 选项头长度。
Ptr: 地址指针字段,是一个基于1的指针,指向存放下一个IP地址的位置。
addr[9]: 记录的Ip地址列表,由于IP首部中选项的空间有限,所以可以记录的Ip地址最多是9个。
3.3、函数功能描述1)InitPing()函数原型:void IntPing()InitPing()函数用于初始化ping 所需的全局变量,为各个变量赋初始值。
2)userHelp()函数原型:void userHelp()userHelp()函数用于显示用户帮助信息。
当程序检查到参数错误或者没有必要的参数(如主机IP地址或者主机名)时,则会调用此函数显示帮助信息。
3) GetArgments()函数原型:void GetArgments(int argc, char**argv)GetArgments()函数用于获取用户提交的参数。
其中argc 表示获取的参数个数,argv 用于存储获取的参数,这两个形参和主函数中的形参表示的意义一样的。
4)checkSum()函数原型:USHORT checkSum(USHORT *buffer,int size)checkSum()函数用于计算校验和。
计算过程是首先把数据报头中的校验和字段设置为0,然后对首部中每个16bit 进行二字段进制反码求和(整个首部看成是由一串16bit的字组成),结果存在校验和字段中。
其中buffer 用于存放ICMP数据,size表示ICMP报文大小。
5)FillCMPData()函数原型:void FillCMPData()FillCMPData()函数用于填充ICMP数据报中各个字段。
其中icmp_data 表示ICMP数据,datasize 表示ICMP报文大小。
6) FreeRes()函数原型:void FreeRes()FreeRes()函数用于释放占用的资源,包括关闭初始化socket 调用的函数的、关闭创建的socket和释放分配的内存等。
7)DecodeIPOptions()函数原型:void DecodeIPOptions()DecodeIPOptions()函数用于解读IP选项,从中读出从源主机到目的主机经过的路由,并输出路由信息。
Buf表示存放接收到的ICMP报文的缓冲区,bytes表示接收到的字节数。
8)DecodeICMPHeader()函数原型:void DecodeICMPHeader(char*buf, int bytes, SOCKADDR_IN*from)DecodeICMPHeader()函数用于解读ICMP报文信息。
Buf表示存放接收到的ICMP报文的缓冲区,bytes 表示接收到的字节数,from 表示发送ICMP回显应答的主机IP地址。
9)PingTest()函数原型:void PingTest(int timeout)PingTest()函数用于进行Ping操作。
其中timeout表示设定的发送超时值。
3.4、程序实现3.4.1、源码分析1. 程序预处理/*导入库文件*/#pragma comment( lib, "ws2_32.lib" )/*加载头文件*/#include <winsock2.h>#include <ws2tcpip.h>#include <stdio.h>#include <stdlib.h>#include <math.h>/*定义常量*//*表示要记录路由*/#define IP_RECORD_ROUTE 0x7/*默认数据报大小*/#define DEF_PACKET_SIZE 32/*最大的ICMP数据报大小*/#define MAX_PACKET 1024/*最大IP头长度*/#define MAX_IP_HDR_SIZE 60/*ICMP报文类型,回显请求*/#define ICMP_ECHO 8/*ICMP报文类型,回显应答*/#define ICMP_ECHOREPL Y 0/*最小的ICMP数据报大小*/#define ICMP_MIN 8/*自定义函数原型*/void InitPing();void UserHelp();void GetArgments(int argc, char** argv);USHORT CheckSum(USHORT *buffer, int size);void FillICMPData(char *icmp_data, int datasize);void FreeRes();void DecodeIPOptions(char *buf, int bytes);void DecodeICMPHeader(char *buf, int bytes, SOCKADDR_IN* from); void PingTest(int timeout);/*IP报头字段数据结构*/typedef struct _iphdr{unsigned int h_len:4; /*IP报头长度*/unsigned int version:4; /*IP的版本号*/unsigned char tos; /*服务的类型*/unsigned short total_len; /*数据报总长度*/unsigned short ident; /*惟一的标识符*/unsigned short frag_flags; /*分段标志*/unsigned char ttl; /*生存期*/unsigned char proto; /*协议类型(TCP、UDP等)*/unsigned short checksum; /*校验和*/unsigned int sourceIP; /*源IP地址*/unsigned int destIP; /*目的IP地址*/} IpHeader;/*ICMP报头字段数据结构*/typedef struct _icmphdr{BYTE i_type; /*ICMP报文类型*/BYTE i_code; /*该类型中的代码号*/USHORT i_cksum; /*校验和*/USHORT i_id; /*惟一的标识符*/USHORT i_seq; /*序列号*/ULONG timestamp; /*时间戳*/} IcmpHeader;/*IP选项头字段数据结构*/typedef struct _ipoptionhdr{unsigned char code; /*选项类型*/unsigned char len; /*选项头长度*/unsigned char ptr; /*地址偏移长度*/unsigned long addr[9]; /*记录的IP地址列表*/} IpOptionHeader;/*定义全局变量*/SOCKET m_socket;IpOptionHeader IpOption;SOCKADDR_IN DestAddr;SOCKADDR_IN SourceAddr;char *icmp_data;char *recvbuf;USHORT seq_no ;char *lpdest;int datasize;BOOL RecordFlag;double PacketNum;BOOL SucessFlag;2.初始化模块/*初始化变量函数*/void InitPing(){WSADA TA wsaData;icmp_data = NULL;seq_no = 0;recvbuf = NULL;RecordFlag = FALSE;lpdest = NULL;datasize = DEF_PACKET_SIZE;PacketNum = 5;SucessFlag = FALSE;/*Winsock初始化*/if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){/*如果初始化不成功则报错,GetLastError()返回发生的错误信息*/printf("WSAStartup() failed: %d\n", GetLastError());return ;}m_socket = INV ALID_SOCKET;}3.功能控制模块/*显示信息函数*/void UserHelp(){printf("UserHelp: ping -r <host> [data size]\n");printf(" -r record route\n");printf(" -n record amount\n");printf(" host remote machine to ping\n");printf(" datasize can be up to 1KB\n");ExitProcess(-1);}/*获取ping选项函数*/void GetArgments(int argc,char** argv){int i;int j;int exp;int len;int m;/*如果没有指定目的地地址和任何选项*/if(argc == 1){printf("\nPlease specify the destination IP address and the ping option as follow!\n");UserHelp();}for(i = 1; i < argc; i++){len = strlen(argv[i]);if (argv[i][0] == '-'){/*选项指示要获取记录的条数*/if(isdigit(argv[i][1])){PacketNum = 0;for(j=len-1,exp=0;j>=1;j--,exp++)/*根据argv[i][j]中的ASCII值计算要获取的记录条数(十进制数)*/PacketNum += ((double)(argv[i][j]-48))*pow(10,exp);}else{switch (tolower(argv[i][1])){/*选项指示要获取路由信息*/case 'r':RecordFlag = TRUE;break;/*没有按要求提供选项*/default:UserHelp();break;}}}/*参数是数据报大小或者IP地址*/else if (isdigit(argv[i][0])){for(m=1;m<len;m++){if(!(isdigit(argv[i][m]))){/*是IP地址*/lpdest = argv[i];break;}/*是数据报大小*/else if(m==len-1)datasize = atoi(argv[i]);}}/*参数是主机名*/elselpdest = argv[i];}}/*求校验和函数*/USHORT CheckSum(USHORT *buffer, int size){unsigned long cksum=0;while (size > 1){cksum += *buffer++;size -= sizeof(USHORT);}if (size){cksum += *(UCHAR*)buffer;}/*对每个16bit进行二进制反码求和*/cksum = (cksum >> 16) + (cksum & 0xffff);cksum += (cksum >>16);return (USHORT)(~cksum);}/*填充ICMP数据报字段函数*/void FillICMPData(char *icmp_data, int datasize){IcmpHeader *icmp_hdr = NULL;char *datapart = NULL;icmp_hdr = (IcmpHeader*)icmp_data;/*ICMP报文类型设置为回显请求*/icmp_hdr->i_type = ICMP_ECHO;icmp_hdr->i_code = 0;/*获取当前进程IP作为标识符*/icmp_hdr->i_id = (USHORT)GetCurrentProcessId();icmp_hdr->i_cksum = 0;icmp_hdr->i_seq = 0;datapart = icmp_data + sizeof(IcmpHeader);/*以数字0填充剩余空间*/memset(datapart,'0',datasize-sizeof(IcmpHeader)); }/*释放资源函数*/void FreeRes(){/*关闭创建的套接字*/if (m_socket != INVALID_SOCKET)closesocket(m_socket);/*释放分配的内存*/HeapFree(GetProcessHeap(), 0, recvbuf);HeapFree(GetProcessHeap(), 0, icmp_data);/*注销WSAStartup()调用*/WSACleanup();return ;}4.数据报解读模块/*解读IP选项头函数*/void DecodeIPOptions(char *buf, int bytes){IpOptionHeader *ipopt = NULL;IN_ADDR inaddr;int i;HOSTENT *host = NULL;/*获取路由信息的地址入口*/ipopt = (IpOptionHeader *)(buf + 20);printf("RR: ");for(i = 0; i < (ipopt->ptr / 4) - 1; i++){inaddr.S_un.S_addr = ipopt->addr[i];if (i != 0)printf(" ");/*根据IP地址获取主机名*/host = gethostbyaddr((char *)&inaddr.S_un.S_addr,sizeof(inaddr.S_un.S_addr), AF_INET);/*如果获取到了主机名,则输出主机名*/if (host)printf("(%-15s) %s\n", inet_ntoa(inaddr), host->h_name);/*否则输出IP地址*/elseprintf("(%-15s)\n", inet_ntoa(inaddr));}return;}/*解读ICMP报头函数*/void DecodeICMPHeader(char *buf, int bytes, SOCKADDR_IN *from){IpHeader *iphdr = NULL;IcmpHeader *icmphdr = NULL;unsigned short iphdrlen;DWORD tick;static int icmpcount = 0;iphdr = (IpHeader *)buf;/*计算IP报头的长度*/iphdrlen = iphdr->h_len * 4;tick = GetTickCount();/*如果IP报头的长度为最大长度(基本长度是20字节),则认为有IP选项,需要解读IP选项*/ if ((iphdrlen == MAX_IP_HDR_SIZE) && (!icmpcount))/*解读IP选项,即路由信息*/DecodeIPOptions(buf, bytes);/*如果读取的数据太小*/if (bytes < iphdrlen + ICMP_MIN){printf("Too few bytes from %s\n",inet_ntoa(from->sin_addr));}icmphdr = (IcmpHeader*)(buf + iphdrlen);/*如果收到的不是回显应答报文则报错*/if (icmphdr->i_type != ICMP_ECHOREPL Y){printf("nonecho type %d recvd\n", icmphdr->i_type);return;}/*核实收到的ID号和发送的是否一致*/if (icmphdr->i_id != (USHORT)GetCurrentProcessId()){printf("someone else's packet!\n");return ;}SucessFlag = TRUE;/*输出记录信息*/printf("%d bytes from %s:", bytes, inet_ntoa(from->sin_addr));printf(" icmp_seq = %d. ", icmphdr->i_seq);printf(" time: %d ms", tick - icmphdr->timestamp);printf("\n");icmpcount++;return;}5.Ping 测试模块/*ping函数*/void PingTest(int timeout){int ret;int readNum;int fromlen;struct hostent *hp = NULL;/*创建原始套接字,该套接字用于ICMP协议*/m_socket = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0,WSA_FLAG_OVERLAPPED);/*如果套接字创建不成功*/if (m_socket == INV ALID_SOCKET){printf("WSASocket() failed: %d\n", WSAGetLastError());return ;}/*若要求记录路由选项*/if (RecordFlag){/*IP选项每个字段用0初始化*/ZeroMemory(&IpOption, sizeof(IpOption));/*为每个ICMP包设置路由选项*/IpOption.code = IP_RECORD_ROUTE;IpOption.ptr = 4;IpOption.len = 39;ret = setsockopt(m_socket, IPPROTO_IP, IP_OPTIONS,(char *)&IpOption, sizeof(IpOption));if (ret == SOCKET_ERROR){printf("setsockopt(IP_OPTIONS) failed: %d\n",WSAGetLastError());}}/*设置接收的超时值*/readNum = setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO,(char*)&timeout, sizeof(timeout));if(readNum == SOCKET_ERROR){printf("setsockopt(SO_RCVTIMEO) failed: %d\n",WSAGetLastError());return ;}/*设置发送的超时值*/timeout = 1000;readNum = setsockopt(m_socket, SOL_SOCKET, SO_SNDTIMEO,(char*)&timeout, sizeof(timeout));if (readNum == SOCKET_ERROR){printf("setsockopt(SO_SNDTIMEO) failed: %d\n",WSAGetLastError());return ;}/*用0初始化目的地地址*/memset(&DestAddr, 0, sizeof(DestAddr));/*设置地址族,这里表示使用IP地址族*/DestAddr.sin_family = AF_INET;if ((DestAddr.sin_addr.s_addr = inet_addr(lpdest)) == INADDR_NONE){/*名字解析,根据主机名获取IP地址*/if ((hp = gethostbyname(lpdest)) != NULL){/*将获取到的IP值赋给目的地地址中的相应字段*/memcpy(&(DestAddr.sin_addr), hp->h_addr, hp->h_length);/*将获取到的地址族值赋给目的地地址中的相应字段*/DestAddr.sin_family = hp->h_addrtype;printf("DestAddr.sin_addr = %s\n", inet_ntoa(DestAddr.sin_addr));}/*获取不成功*/else{printf("gethostbyname() failed: %d\n",WSAGetLastError());return ;}}/*数据报文大小需要包含ICMP报头*/datasize += sizeof(IcmpHeader);/*根据默认堆句柄,从堆中分配MAX_PACKET内存块,新分配内存的内容将被初始化为0*/ icmp_data =(char*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,MAX_PACKET); recvbuf =(char*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,MAX_PACKET);/*如果分配内存不成功*/if (!icmp_data){printf("HeapAlloc() failed: %d\n", GetLastError());return ;}/* 创建ICMP报文*/memset(icmp_data,0,MAX_PACKET);FillICMPData(icmp_data,datasize);while(1){static int nCount = 0;int writeNum;/*超过指定的记录条数则退出*/if (nCount++ == PacketNum)break;/*计算校验和前要把校验和字段设置为0*/((IcmpHeader*)icmp_data)->i_cksum = 0;/*获取操作系统启动到现在所经过的毫秒数,设置时间戳*/((IcmpHeader*)icmp_data)->timestamp = GetTickCount();/*设置序列号*/((IcmpHeader*)icmp_data)->i_seq = seq_no++;/*计算校验和*/((IcmpHeader*)icmp_data)->i_cksum = CheckSum((USHORT*)icmp_data, datasize);/*开始发送ICMP请求*/writeNum = sendto(m_socket, icmp_data, datasize, 0,(struct sockaddr*)&DestAddr, sizeof(DestAddr));/*如果发送不成功*/if (writeNum == SOCKET_ERROR){/*如果是由于超时不成功*/if (WSAGetLastError() == WSAETIMEDOUT){printf("timed out\n");continue;}/*其他发送不成功原因*/printf("sendto() failed: %d\n", WSAGetLastError());return ;}/*开始接收ICMP应答*/fromlen = sizeof(SourceAddr);readNum = recvfrom(m_socket, recvbuf, MAX_PACKET, 0,(struct sockaddr*)&SourceAddr, &fromlen);/*如果接收不成功*/if (readNum == SOCKET_ERROR){/*如果是由于超时不成功*/if (WSAGetLastError() == WSAETIMEDOUT){printf("timed out\n");continue;}/*其他接收不成功原因*/printf("recvfrom() failed: %d\n", WSAGetLastError());return ;}/*解读接收到的ICMP数据报*/DecodeICMPHeader(recvbuf, readNum, &SourceAddr);}}6.主函数int main(int argc, char* argv[]){InitPing();GetArgments(argc, argv);PingTest(1000);/*延迟1秒*/Sleep(1000);if(SucessFlag)printf("\nPing end, you have got %.0f records!\n",PacketNum);elseprintf("Ping end, no record!");FreeRes();getchar();return 0;}21。
Ping 程序设计原理(2023最新版)
Ping 程序设计原理⒈引言本文档旨在介绍 Ping 程序设计原理,包括其概述、设计原则和实现细节。
Ping 是一种网络工具,用于测试主机之间的网络连通性。
本文将讨论 Ping 的基本原理、实现方法以及使用示例。
⒉概述Ping 是一种基于 ICMP(Internet Control Message Protocol)的网络工具,它通过向目标主机发送 ICMP 回显请求消息(Echo Request)并等待目标主机的 ICMP 回显应答消息(Echo Reply)来测试主机之间的连通性。
⒊设计原则在设计 Ping 程序时,需要考虑以下原则:- 网络层协议:Ping 使用 ICMP 协议进行通信,所以需要对ICMP 协议进行理解和实现。
- 数据包处理:Ping 程序需要构造 ICMP 回显请求消息,并解析目标主机的 ICMP 回显应答消息。
- 超时机制:Ping 程序需要设置合理的超时时间,如果在超时时间内未接收到回显应答,则认为连接超时。
- 循环测试:Ping 程序可以通过循环发送 ICMP 回显请求消息来进行连通性测试。
⒋实现细节⑴ ICMP 协议ICMP 是一种网络层协议,用于在 IP 网络中传递错误消息和操作性消息。
在 Ping 程序中,我们使用 ICMP 协议来进行主机之间的连通性测试。
⑵构造 ICMP 回显请求消息Ping 程序在发送 ICMP 回显请求消息时,需要构造相应的数据包。
构造 ICMP 数据包过程需要设置以下字段:- 类型:设置为 8,表示 ICMP 回显请求消息。
- 代码:通常设为 0。
- 校验和:对 ICMP 数据包进行校验和计算。
- 标识符和序列号:用于识别 ICMP 回显请求消息和回显应答消息之间的对应关系。
- 数据:可以包含任意数据,用于传递给目标主机处理。
⑶解析 ICMP 回显应答消息Ping 程序在接收到目标主机的 ICMP 回显应答消息时,需要解析其内容。
解析 ICMP 数据包时,需要检查以下字段:- 类型:应为 0,表示 ICMP 回显应答消息。
计算机网络课程设计实验报告
计算机网络课程设计报告姓名:学号:班级:指导老师:湖南科技大学计算机科学与工程学院2013年6月实验一1。
实验名称:网络聊天程序的设计与实现2。
实验目的:通过本实验能够了解socket通信的原理并在此基础上编写一个聊天程序了解TCP/IP的基础知识,发现TCP与UDP的优缺点以及在网络通信的应用.3.实验原理:从通信和信息处理的角度看,运输层向它上面的应用层提供通信服务,它属于面向通信部分的最高层,同时也是用户功能中的最低层。
当网络的边缘部分中的两个主机使用网络的两个主机使用网络的核心部分进行端到端的通信时,只有主机的协议栈才有运输层,而网络核心部分中的路由器在转发分组时都只用到下三层的功能。
从IP层来说,通信的两端是两个主机,IP数据报的首部明确的标志了这两个主机的IP地址.但是严格的讲,两个主机进行通信就是两个主机中的应用进程互相通信。
根据应用程序的不同需求,运输层需要有两种不同的运输协议,即是面向连接的TCP和无连接的UDP。
在使用这两个协议时运输层向高层用户屏蔽了下面的网络核心的细节,它使应用进程看见的就是好像在两个运输层实体间有一条端到端的逻辑通信信道,但这条逻辑通信信道对上层的表现却因运输层使用的不同协议而有很大的差别.当运输层采用面向连接的TCP协议时,尽管下面的网络是不可靠的,但这种逻辑通信信道就相当于一条全双工的可靠信道。
但当运输层采用无连接的UDP协议时,这种逻辑通信信道仍然是一条不可靠信道.由于我在课程设计中采用的是UDP协议进行通信的,这里就只简述一下一些关于UDP的内容,UDP在传送数据之前不需要先建立连接。
远地主机的运输层在收到UDP报文后,不需要给出任何确认。
虽然UDP不提供可靠的交付,但在某些情况下UDP却是一种最有效的工作方式.为此当我们使用UTP协议使两个计算机中的进程要互相通信,不仅必需知道对方的IP地址(为了找到对方的计算机),而且还要知道对方的端口号(为了找到对方计算机中的应用进程)。
间接平差程序设计
printM(fp,V,n,1,"%10.3lf","观测值的改正数(V)",true); //输出改正数v
printM(fp,X,r,1,"%10.3lf","参数x近似值",true); //输出参数x
{
FILE* fp=fopen(filename,"r");
if(fp==NULL)
{
MessageBox("数据文件打开失败!");
return;
}
int n,r;
fscanf(fp,"%d%d",&n,&r);
double *B=new double[n*r];
double* P=new double[n];
}
a[n*(n+1)/2-1]=1.0/a00;
}
delete []a0;
return计算函数代码
int CPingcDlg::ij(int i, int j)
{
return (i>=j)?i*(i+1)/2+j:j*(j+1)/2+i;
}
//间接平差计算函数代码
double CPingcDlg::jianjie(int n, int r, double B[], double P[],double L[], double V[], double X[])
N[ij(i,j)]=nij;
}
}
//矩阵W计算
double *W=new double[r];
计算机网络基础课程设计Ping程序实现
计算机网络基础课程设计Ping程序实现计算机网络工程课程设计报告题目:Ping程序的实现学生姓名:学号:专业班级:计科专业班同组姓名: 指导教师:设计时间:2022年下学期第某周指导老师意见:评定成绩:签名:日期:年月日目录一、课程设计的目的和意义2二、课程设计的内容和要求21.内容:22.要求:2三、课程设计的相关技术2四、课程设计过程21.Ping主模块22.功能控制模块43.数据报解析模块5五、课程设计小结6六、参考文献7七、附录(程序清单)7八、心得体会11一、课程设计的目的和意义利用ICMP数据包、C语言实现Ping命令程序,能实现基本的Ping操作,发送ICMP回显请求报文,用于测试—个主机到只一个主机之间的连通情况。
通过本程序的训练,使学生熟悉ICMP报文结构,使学生对ICMP有更深的理解,掌握Ping程序的设计方法,掌握网络编程的方法和技巧,从而编写出功能更强大的程序。
二、课程设计的内容和要求1.内容:用C语言实现Ping命令程序,能实现基本的Ping操作,发送ICMP回显请求报文,用于测试—个主机到只一个主机之间的连通情况。
2.要求:1)独立完成程序的设计、编码和调试。
2)系统利用C语言实现,程序调试环境为TurboC或VC;3)按照课程设计规范书写课程设计报告。
4)采用VC环境进行调试运行。
三、课程设计的相关技术由于Ping程序是面向用户的应用程序,该程序使用ICMP的封装机制,通过IP协议来工作。
为了实现直接对IP和ICMP包进行操作,实验中使用RAW模式的ocket编程。
首先定义IP数据报首部,在IP数据报的基础上定义ICMP数据报首部,并初始化一些全局变量。
接着自定义填充ICMP数据报字段函数FillICMPData()、校验和函数checkum()、解读ICMP报首部函数DecodeICMPHeader()、释放资源函Cleanup()。
最后主函数通过调用这些函数来实现Ping命令功能。
ping程序设计与实现课程设计
ping程序设计与实现课程设计一、课程目标知识目标:1. 学生能理解ping程序的工作原理,掌握网络诊断的基本方法。
2. 学生能描述IP协议、ICMP协议的基本概念及其在ping程序中的应用。
3. 学生了解计算机网络的通信原理,掌握如何利用ping程序检测网络连通性。
技能目标:1. 学生能运用所学知识,独立编写简单的ping程序。
2. 学生通过实践操作,提高问题分析及解决能力,具备基本的网络诊断技巧。
3. 学生掌握使用编程工具(如:IDE、编译器等)进行代码编写、调试和优化。
情感态度价值观目标:1. 学生培养对计算机网络的兴趣,激发学习编程的热情。
2. 学生在学习过程中,培养团队协作、沟通表达的能力,增强自信心。
3. 学生通过本课程的学习,认识到网络技术在实际应用中的重要性,培养对网络安全的责任感。
分析课程性质、学生特点和教学要求,本课程旨在让学生掌握ping程序的设计与实现,结合实际操作,提高学生的编程能力和网络诊断技巧。
课程目标具体、可衡量,有助于教师进行教学设计和评估。
通过本课程的学习,学生将具备基本的网络编程知识和技能,为今后的学习和工作打下坚实基础。
二、教学内容1. 网络基础知识回顾:IP协议、ICMP协议、网络层通信原理。
2. ping程序工作原理:发送ICMP请求、接收ICMP回复、计算往返时间(RTT)。
3. 编程语言基础:C语言或Python语言的基本语法,重点掌握数据类型、控制结构、函数定义。
4. ping程序设计与实现:- 环境搭建:安装编程工具、配置网络环境。
- 代码编写:根据ping程序工作原理,编写发送和接收ICMP请求的代码。
- 调试与优化:调试代码,处理异常情况,优化程序性能。
5. 实践操作:分组进行实际操作,组内讨论、分析问题,相互协作完成ping 程序编写。
6. 网络诊断技巧:运用ping程序检测网络连通性,分析网络延迟、丢包等问题。
教学内容安排和进度:第一课时:网络基础知识回顾,介绍ping程序工作原理。
编程模拟ping程序
一、实验题目编程模拟ping程序,实现Ping程序的基本功能,即接收到一个ping程序数据包后给出回应。
二、原理概述ping命令是用来查看网络上另一个主机系统的网络连接是否正常的一个工具。
ping命令的工作原理是:向网络上的另一个主机系统发送ICMP报文,如果指定系统得到了报文,它将把报文一模一样地传回给发送者,这有点象潜水艇声纳系统中使用的发声装置。
想要了解ping命令的原理必须了解ICMP协议、ICMP报文格式和IP报文格式。
(1)ICMP报文结构ICMP 报文结构: ICMP 报文前四个字节为报文头部分,第一个字节为报文类型,第二个字节未用, 第三四个字节为报文的校验和。
从第四个字节开始为长度可变的数据段,该段的内容取决于ICMP 的类型,本文所要使用的请求报文和请求应答报文的数据段中前四个字节是报文的标识符和顺序号。
对于整个ICMP 报文来说其长度最长不能超过64K字节。
ICMP 报文结构如图1 所示。
0 7 8 15 16 31 32 47 48 63 64(2)IP报文结构ICMP 报文和其它位于IP 层的报文一样是作为IP 报文的数据段加上IP 报文头组成IP 数据报发出,其中IP 报文头长度一般为20 个字节。
如图2所示。
三、设计方案根据实验题目查找相关资料,熟悉及理解ping的工作原理,从而进一步设计ping程序的功能图和系统流程图。
准备工作做好后就可上机调试,验证其可行性并查找漏洞,完善ping程序。
(1) ping程序的设计包含了4部分:IP、ICMP的头结构,主函数模块,CMP数据包校验和的计算和使用说明模块。
(2)系统流程图首先在主函数里定义变量同时进行初始化,然后检查参数的正确性,如果参数不正确或者没有输入参数,则显示用户帮助信息(Usage ),并结束程序;如果参数正确,则对指定目的地执行Ping命令,如果Ping通,则显示Ping结果并释放占用资源,如果没有Ping通,则报告错误信息,并释放占用资源。
ping程序的设计与实现
ping程序的设计与实现
Ping程序的设计与实现是通过一种单向测量技术来实现的,它可以用来评估网络的性能、访问故障和网络可用性。
Ping程序工作时会首先向目标主机发送一个ICMP(网际控制报文协议)报文,然后等待目标主机的应答。
在实现ping程序的过程中,首先要为发送的ICMP数据报定义一个数据结构,这个数据结构将包含所有必要的信息,如报文类型、报文代码、校验和等。
其次,要实现函数,对这个数据结构进行填充和序列化,以便将ICMP报文发送出去。
实现发送ICMP报文后,就要开始接收应答。
为此,可以利用Socket API来创建一个Raw Socket,以便从网络上接收ICMP报文,并将其解码为数据结构,以便能够识别是哪一条报文的应答。
最后,还需要实现超时,用来处理因网络拥塞或丢包等原因导致的应答报文没有收到的情况。
这可以通过在发送ICMP报文之前先设置一个定时器,当定时器到期时,就可以判断该报文没有收到应答报文而超时。
以上就是ping程序的大致设计与实现方式,整个实现的过程可以大体分为发送ICMP数据报、接收应答和超时处理三部分。
这些都需要对数据报结构进行定义和填充,以及使用Socket API创建Raw Socket 来发送和接收数据,并通过设置定时器来实现超时处理,以保证ping 程序可以正常工作。
ping程序课程设计设计背景
ping程序课程设计设计背景一、教学目标本章节的教学目标包括以下三个方面:1.知识目标:学生能够理解ping程序的基本概念,掌握使用ping程序进行网络诊断的方法和技巧。
2.技能目标:学生能够独立操作计算机,使用ping程序对网络进行诊断,并能根据诊断结果分析网络状况。
3.情感态度价值观目标:学生通过学习ping程序的使用,增强对网络技术的兴趣和好奇心,培养解决问题的能力,提高对网络技术的应用意识和信息素养。
二、教学内容本章节的教学内容主要包括以下几个部分:1.ping程序的基本概念和作用。
2.ping程序的使用方法,包括命令的输入、参数的含义和如何解读ping结果。
3.ping程序在网络诊断中的应用,如何通过ping程序检测网络的连接性、延迟和数据包丢失情况。
4.实际操作演练,让学生通过实际操作,掌握ping程序的使用技巧。
三、教学方法为了实现本章节的教学目标,我们将采用以下几种教学方法:1.讲授法:通过讲解ping程序的基本概念、使用方法和网络诊断中的应用,让学生掌握相关知识。
2.案例分析法:通过分析实际案例,让学生了解ping程序在网络诊断中的实际应用,提高解决问题的能力。
3.实验法:让学生亲自动手操作,进行网络诊断实验,培养实际操作能力和动手能力。
四、教学资源为了支持本章节的教学内容和教学方法的实施,我们将准备以下教学资源:1.教材:《网络技术基础》2.参考书:《计算机网络与应用》3.多媒体资料:网络诊断实验演示视频4.实验设备:计算机、网络设备(如路由器、交换机等)五、教学评估本章节的教学评估主要包括以下几个方面:1.平时表现:通过观察学生在课堂上的参与程度、提问回答情况等,评估学生的学习态度和积极性。
2.作业:通过学生提交的作业,评估学生对ping程序的理解和掌握程度。
3.考试:通过期末考试,全面测试学生对ping程序的知识掌握和实际操作能力。
评估方式应客观、公正,能够全面反映学生的学习成果。
纯Javascript实现ping功能的方法
Linux网络编程基础(4)--Ping的C代码实现
Linux⽹络编程基础(4)--Ping的C代码实现1、背景 在进⾏⽹络编程的时候,通常使⽤的协议有TCP协议,UDP协议。
这些协议在简历套接字之初需要制定套接字的类型,⽐如TCP应当设置为 SOCK_STREAM,UDP对应的套接字应当设置为SOCK_DGRAM。
但是这些套接字并⾮能够提供⽹络所需的全部功能,我们还需要其他的套接字,⽐如原始套接字OCK_RAW。
原始套接字可以提供SOCK_STREAM和SOCK_DGRAM所不及的能⼒。
⽐如:(1)有了原始套接字,进程可以读取ICMPV4、ICMPV6、IGMP等的分组。
正如ping所使⽤的套接字,就是SOCK_RAW类型的。
这样使得使⽤ICMP和IGMP的程完全能够作为⽤户进程处理,⽽⽆需向内核添加代码。
(2)有了原始套接字,进程可以处理内核不处理其协议字段的IPV4数据报。
(3)有了原始套接字,进程使⽤IP_HDRINCL套接字选项定制⾃⼰的IPV4头部。
当然,上述的三个功能,并不是本⽂都要涉及的;只关注第⼀个能⼒,编写代码,实现ping程序。
2、基本使⽤ a.定义原始套接字与定义其他套接字没有形式上的巨⼤差别。
int sockfd; sockfd = socket(AF_INET, SOCK_RAW, protocol); protocol 的值是型为 IPPROTO_XXX的量,这些量定义在<netinet/in.h>中,⽐如ping使⽤的 IPPROTO_ICMP(关于IPV6的实现,再后续补充)。
只有超级⽤户才可以创建SOCK_RAW类型的套接字。
b. 原始套接字并不存在端⼝的概念。
可以在原始套接字上调⽤bind函数,但是这么做并不常见。
bind函数会设置发送数据报的源IP地址,如果没有使⽤ bind函数,那么内核将出发的借⼝地址作为源地址。
c. 同样,⼀般不会使⽤connect函数,connect函数会指定⽬的地址,但是因为原始套接字不存在端⼝概念,所以connect函数并不重要了。
