您好,欢迎访问三七文档
当前位置:首页 > 行业资料 > 其它行业文档 > 利用VisualC实现ICMP网络协议
利用VisualC#实现ICMP网络协议ICMP就是所谓的Internet控制报文协议(InternetControlMessageProtocol),在网络中,一般用它来传递差错报文以及其他应注意的信息。ICMP一般被认为是和IP协议同一层的协议,IMCP报文通常被IP层或者更高层的协议(如:TCP或者UDP)使用,ICMP对于互联网以及其他基于IP协议的网络的正常运行起着非常重要的作用。有许多重要的网络程序都是基于ICMP协议上的,最为著名如Ping和Tracert等。本文就来介绍用VisualC#实现基于ICMP协议重要的网络命令Ping的方法。Ping命令是可以说是一个跨平台程序,这是因为Ping命令不仅存在Windows系统上,在Unix系统上也有Ping命令,其实对其他只要是支持网络的操作系统,一般也都存在该命令。Ping命令的主要作用是检测网络上主机的状态。要是在几年前,我们还可以下如此断言,如果不能Ping通某台主机,那么也就无法Telnet或者FTP到这台主机,但随着互联网的安全意识的增加,出现了访问控制清单的路由器和防火墙,由于ICMP报文是在IP数据包中被传输的,而到达一台主机不仅取决于IP层是否到达,还取决于使用何种协议和端口。譬如金山公司的金山网镖就可以禁止其他机器Ping通这台主机。所以在现在的情况下,即时Ping不通某台机器,但也有可能FTP登陆到这台机器,或者通过HTTP来浏览这台机器上的Web页面。一.Ping命令简介首先进入Windows系统中的命令提示符,输入Ping/?后,单击回车键,您就可以了解Ping命令的各种参数的使用方法。最为常见的使用方法是Ping远程计算机名称(或者远程计算机的IP地址),如果在Ping命令的返回字符中有Replyfrom,说明此主机在线,具体如图01:图01:Ping通主机时的运行界面如果返回字符中有Requesttimeout,一般情况此主机不在线,具体如图02:图02:Ping不通主机时的运行界面二.Ping命令、ICMP报文和IP数据包Ping命令基于的是TCP/IP协议簇中的ICMP协议,在编写基于ICMP协议的网络应用程序时,应注意下面二点:1.ICMP报文是封装在IP数据包中传输的。了解这一点对后面编程非常重要,图03是IP数据包的组成结构图:图03:IP数据包的组成结构图习惯上把IP数据包划分为三个部分:(1).IP数据包中的前二十个字节的数据,即图03中从【4位版本】到【32位目的地址IP】,这称为IP首部。(2).选项,即图03中的【选项(如果有)】部分。(3).数据,即图03中的【数据】部分。其中后面二个部分组成的就是ICMP报文。ICMP报文的具体组成结构如图04所示:图04:ICMP报文组成结构图2.ICMP协议没有固定的端口号。ICMP协议和其他协议不同,其他协议基本都对应固定的端口号,如HTTP协议是通过80端口号来交换数据的。了解上面的二点对后面在VisualC#实现Ping命令是非常有用的。因为在下面的在编写VisualC#实现Ping命令的程序中,程序中定义一个名称为IcmpPacket类,通过这个类来构造ICMP报文,而定义IcmpPacket类依据的就是图03所示的ICMP报文组成结构。同样由于ICMP协议没有对应固定的端口号,这就意味着,编写VisualC#实现Ping命令中可以随意选择端口号,本文选择的端口号是30。由于ICMP协议是一个复杂的协议,而本文由于篇幅所限,对ICMP的很多细节,就不能一一介绍,如果你对ICMP协议感兴趣或对上面的介绍的仍然感觉有点模糊,那就请参阅探讨ICMP协议的相关书籍,它们一般介绍的都很详细。三.简介VisualC#实现Ping命令使用的类:VisualC#实现Ping命令中涉及到很多的类,其中最重要的是Socket类。这是因为程序中发送含有ICMP报文的IP数据包,接收含有ICMP超时或ICMP会显报文的IP数据包和设定IP数据包中的TTL数值都会使用到Socket类。表01和表02是Socket类中的常用属性和方法及其简要说明。属性说明AddressFamily获取Socket的地址族。Available获取已经从网络接收且可供读取的数据量。Blocking获取或设置一个值,该值指示Socket是否处于阻塞模式。Connected获取一个值,该值指示Socket是否已连接到远程资源。Handle获取Socket的操作系统句柄。LocalEndPoint获取本地终结点。ProtocolType获取Socket的协议类型。RemoteEndPoint获取远程终结点。SocketType获取Socket的类型。表01:Socket类的常用属性及其说明方法说明Accept创建新的Socket以处理传入的连接请求。BeginAccept开始一个异步请求,以创建新的Socket来接受传入的连接请求。BeginConnect开始对网络设备连接的异步请求。BeginReceive开始从连接的Socket中异步接收数据。BeginReceiveFrom开始从指定网络设备中异步接收数据。BeginSend将数据异步发送到连接的BeginSendTo向特定远程主机异步发送数据。Bind使Socket与一个本地终结点相关联。Close强制Socket连接关闭。Connect建立到远程设备的连接。EndAccept结束异步请求以创建新的Socket来接受传入的连接请求。EndConnect结束挂起的异步连接请求。EndReceive结束挂起的异步读取。EndReceiveFrom结束挂起的、从特定终结点进行异步读取。EndSend结束挂起的异步发送。EndSendTo结束挂起的、向指定位置进行的异步发送。GetSocketOption返回Socket选项的值。IOControl为Socket设置低级别操作模式。Listen将Socket置于侦听状态。Poll确定Socket的状态。Receive接收来自连接Socket的数据。ReceiveFrom接收数据文报并存储源终结点。Select确定一个或多个套接字的状态。Send将数据发送到连接的SendTo将数据发送到特定终结点。SetSocketOption设置Socket选项。Shutdown禁用某Socket上的发送和接收。表02:Socket类的常用方法及其说明其中包含六组异步方法,它们是:·BeginAccept和EndAccept·BeginConnect和EndConnect·BeginReceive和EndReceive·BeginReceiveFrom和EndReceiveFrom·BeginSend和EndSend·BeginSendTo和EndSendTo其功能分别相当于Accept、Connect、Receive、ReceiveFrom、Send和SendTo方法。四.VisualC#实现Ping命令的关键步骤及其解决方法根据Ping命令的执行过程,可以把Ping命令分成三个主要的步骤:1.定义ICMP报文。2.客户机发送封装ICMP回显请求报文的IP数据包。3.客户机接收封装ICMP应答报文的IP数据包。解决了上述三个步骤,VisualC#实现Ping命令就基本可以完成了。下面是这三个步骤的具体的解决方法。1.定义ICMP报文:根据图05所示的ICMP报文组成结构,定义了一个类--IcmpPacket类。IcmpPacket类通过实例化就能够得到ICMP报文。下面代码是定义IcmpPacket类:publicclassIcmpPacket{privateByte_type;//类型privateByte_subCode;//代码privateUInt16_checkSum;//校验和privateUInt16_identifier;//识别符privateUInt16_sequenceNumber;//序列号privateByte[]_data;//选项数据publicIcmpPacket(Bytetype,BytesubCode,UInt16checkSum,UInt16identifier,UInt16sequenceNumber,intdataSize){_type=type;_subCode=subCode;_checkSum=checkSum;_identifier=identifier;_sequenceNumber=sequenceNumber;_data=newByte[dataSize];//在数据中,写入指定的数据大小for(inti=0;idataSize;i++){//由于选项数据在此命令中并不重要,所以你可以改换任何你喜欢的字符_data[i]=(byte)'#';}}publicUInt16CheckSum{get{return_checkSum;}set{_checkSum=value;}}//初始化ICMP报文publicintCountByte(Byte[]buffer){Byte[]b_type=newByte[1]{_type};Byte[]b_code=newByte[1]{_subCode};Byte[]b_cksum=BitConverter.GetBytes(_checkSum);Byte[]b_id=BitConverter.GetBytes(_identifier);Byte[]b_seq=BitConverter.GetBytes(_sequenceNumber);inti=0;Array.Copy(b_type,0,buffer,i,b_type.Length);i+=b_type.Length;Array.Copy(b_code,0,buffer,i,b_code.Length);i+=b_code.Length;Array.Copy(b_cksum,0,buffer,i,b_cksum.Length);i+=b_cksum.Length;Array.Copy(b_id,0,buffer,i,b_id.Length);i+=b_id.Length;Array.Copy(b_seq,0,buffer,i,b_seq.Length);i+=b_seq.Length;Array.Copy(_data,0,buffer,i,_data.Length);i+=_data.Length;returni;}//将整个ICMP报文信息和数据转化为Byte数据包publicstaticUInt16SumOfCheck(UInt16[]buffer){intcksum=0;for(inti=0;ibuffer.Length;i++)cksum+=(int)buffer[i];cksum=(cksum16)+(cksum&0xffff);cksum+=(cksum16);return(UInt16)(~cksum);}}下列代码是利用IcmpPacket类来创建ICMP报文:IcmpPacketpacket=newIcmpPacket(0,0,0,45,0,4);此代码定义的ICMP报文中的数据段长度为4个字节,所以整个ICMP报文长度为12个字节(即:8+4),而封装此ICMP报文的IP数据包长度就是32个字节(即:8+4+20)。在后面介绍的程序中,从客户端发送的ICMP会显请求报文的数据长度为4个字节,但从服务器介绍到的数据却是32个字节的原因。2.发送封装ICMP回显请求报文的IP数据包:发送IP数据包首先要创建一个能够发送封装ICMP回显请求报文的IP数据包Socket实例,然后调用此Socket实例中的SendTo方法就可以了。下列代码是创建并初始化一个发送封装ICMP回显请求报文的IP数据包的Socket实例:Socketsocket=newSocket(AddressFamily.InterNetwork,SocketType.Raw,ProtocolTy
本文标题:利用VisualC实现ICMP网络协议
链接地址:https://www.777doc.com/doc-2667211 .html