c#下实现ping操作

1、利用原始Socket套接字,实现ICMP协议。



using System; 
using
 System.Collections.Generic; 
using
 System.Text; 
using
 System.Net; 
using
 System.Net.Sockets; 


namespace
 PingC 

    
class
 ping 
    { 
        
const int SOCKET_ERROR = -1

        
const int ICMP_ECHO = 8

        
static void Main(string
[] args) 
        { 
            ping p 
= new
 ping(); 
            Console.WriteLine(
"请输入要 Ping 的IP或者主机名字:"
); 
            
string MyUrl =
 Console.ReadLine(); 
            Console.WriteLine(
"正在 Ping " + MyUrl + " ……"
); 
            Console.Write(p.PingHost(MyUrl)); 
        } 
        
public string PingHost(string
 host) 
        { 
            
// 声明 IPHostEntry 

            IPHostEntry ServerHE, fromHE; 
            
int nBytes = 0

            
int dwStart = 0, dwStop = 0


            
//初始化ICMP的Socket 

            Socket socket = 
             
new
 Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp); 
            socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 
1000
); 
            
// 得到Server EndPoint 

            try 
            { 
                ServerHE 
=
 Dns.GetHostByName(host); 
            } 
            
catch
 (Exception) 
            { 

                
return "没有发现主机"

            } 

            
// 把 Server IP_EndPoint转换成EndPoint 

            IPEndPoint ipepServer = new IPEndPoint(ServerHE.AddressList[0], 0); 
            EndPoint epServer 
=
 (ipepServer); 

            
// 设定客户机的接收Endpoint 

            fromHE = Dns.GetHostByName(Dns.GetHostName()); 
            IPEndPoint ipEndPointFrom 
= new IPEndPoint(fromHE.AddressList[0], 0
); 
            EndPoint EndPointFrom 
=
 (ipEndPointFrom); 

            
int PacketSize = 0

            IcmpPacket packet 
= new
 IcmpPacket(); 

            
// 构建要发送的包 

            packet.Type = ICMP_ECHO; //
            packet.SubCode = 0
            packet.CheckSum 
=0

            packet.Identifier 
= 45

            packet.SequenceNumber 
= 0

            
int PingData = 24// sizeof(IcmpPacket) - 8; 

            packet.Data = new Byte[PingData]; 

            
// 初始化Packet.Data 

            for (int i = 0; i < PingData; i++
            { 
                packet.Data[i] 
= (byte)'#'

            } 

            
//Variable to hold the total Packet size 

            PacketSize = 32
            Byte[] icmp_pkt_buffer 
= new
 Byte[PacketSize]; 
            Int32 Index 
= 0

            
//again check the packet size 

            Index = Serialize( 
             packet, 
             icmp_pkt_buffer, 
             PacketSize, 
             PingData); 
            
//if there is a error report it 

            if (Index == -1
            { 
                
return "Error Creating Packet"


            } 
            
//
 convert into a UInt16 array 

            
//Get the Half size of the Packet 

            Double double_length = Convert.ToDouble(Index); 
            Double dtemp 
= Math.Ceiling(double_length / 2
); 
            
int cksum_buffer_length = Index/2

            
//Create a Byte Array 

            UInt16[] cksum_buffer = new UInt16[cksum_buffer_length]; 
            
//Code to initialize the Uint16 array 

            int icmp_header_buffer_index = 0
            
for (int i = 0; i < cksum_buffer_length; i++

            { 
                cksum_buffer[i] 
=
 
                 BitConverter.ToUInt16(icmp_pkt_buffer, icmp_header_buffer_index); 
                icmp_header_buffer_index 
+= 2

            } 
            
//Call a method which will return a checksum 

            UInt16 u_cksum = checksum(cksum_buffer, cksum_buffer_length); 
            
//Save the checksum to the Packet 

            packet.CheckSum = u_cksum; 

            
// Now that we have the checksum, serialize the packet again 

            Byte[] sendbuf = new Byte[PacketSize]; 
            
//again check the packet size 

            Index = Serialize( 
             packet, 
             sendbuf, 
             PacketSize, 
             PingData); 
            
//if there is a error report it 

            if (Index == -1
            { 
                
return "Error Creating Packet"


            } 

            dwStart 
= System.Environment.TickCount; //
 Start timing 
            
//send the Packet over the socket 

            if ((nBytes = socket.SendTo(sendbuf, PacketSize, 0, epServer)) == SOCKET_ERROR) 
            { 
                
return "Socket Error: cannot send Packet"

            } 
            
//
 Initialize the buffers. The receive buffer is the size of the 
            
// ICMP header plus the IP header (20 bytes) 

            Byte[] ReceiveBuffer = new Byte[256]; 
            nBytes 
= 0

            
//Receive the bytes 

            bool recd = false
            
int timeout = 0


            
//loop for checking the time of the server responding 

            while (!recd) 
            { 
                nBytes 
= socket.ReceiveFrom(ReceiveBuffer, 2560ref
 EndPointFrom); 
                
if (nBytes ==
 SOCKET_ERROR) 
                { 
                    
return "主机没有响应"


                } 
                
else if (nBytes > 0

                { 
                    dwStop 
= System.Environment.TickCount - dwStart; // stop timing 

                    return "Reply from " + epServer.ToString() + " in " 
                    
+ dwStop + "ms.  Received: " + nBytes + " Bytes."


                } 
                timeout 
= System.Environment.TickCount -
 dwStart; 
                
if (timeout > 1000

                { 
                    
return "超时"

                } 
            } 

            
//close the socket 

            socket.Close(); 
            
return ""

        } 
        
/// <summary>
 
        
///
  This method get the Packet and calculates the total size 
        
///
  of the Pack by converting it to byte array 
        
/// </summary> 

        public static Int32 Serialize(IcmpPacket packet, Byte[] Buffer, 
         Int32 PacketSize, Int32 PingData) 
        { 
            Int32 cbReturn 
= 0

            
// serialize the struct into the array 

            int Index = 0

            Byte[] b_type 
= new Byte[1
]; 
            b_type[
0=
 (packet.Type); 

            Byte[] b_code 
= new Byte[1
]; 
            b_code[
0=
 (packet.SubCode); 

            Byte[] b_cksum 
=
 BitConverter.GetBytes(packet.CheckSum); 
            Byte[] b_id 
=
 BitConverter.GetBytes(packet.Identifier); 
            Byte[] b_seq 
=
 BitConverter.GetBytes(packet.SequenceNumber); 

            Array.Copy(b_type, 
0
, Buffer, Index, b_type.Length); 
            Index 
+=
 b_type.Length; 

            Array.Copy(b_code, 
0
, Buffer, Index, b_code.Length); 
            Index 
+=
 b_code.Length; 

            Array.Copy(b_cksum, 
0
, Buffer, Index, b_cksum.Length); 
            Index 
+=
 b_cksum.Length; 

            Array.Copy(b_id, 
0
, Buffer, Index, b_id.Length); 
            Index 
+=
 b_id.Length; 

            Array.Copy(b_seq, 
0
, Buffer, Index, b_seq.Length); 
            Index 
+=
 b_seq.Length; 

            
// copy the data 

            Array.Copy(packet.Data, 0, Buffer, Index, PingData); 
            Index 
+=
 PingData; 
            
if (Index != PacketSize/* sizeof(IcmpPacket)  */

            { 
                cbReturn 
= -1

                
return
 cbReturn; 
            } 

            cbReturn 
=
 Index; 
            
return
 cbReturn; 
        } 
        
/// <summary>
 
        
///
  This Method has the algorithm to make a checksum 
        
/// </summary> 

        public static UInt16 checksum(UInt16[] buffer, int size) 
        { 
            Int32 cksum 
= 0

            
int
 counter; 
            counter 
= 0


            
while (size > 0

            { 
                UInt16 val 
=
 buffer[counter]; 

                cksum 
+=
 buffer[counter]; 
                counter 
+= 1

                size 
-= 1

            } 

            cksum 
= (cksum >> 16+ (cksum & 0xffff
); 
            cksum 
+= (cksum >> 16
); 
            
return (UInt16)(~
cksum); 
        } 
    } 
    
///
 类结束 
    
/// <summary>
 
    
///
  Class that holds the Pack information 
    
/// </summary> 

    public class IcmpPacket 
    { 
        
public Byte Type;    // type of message 

        public Byte SubCode;    // type of sub code 
        public UInt16 CheckSum;   // ones complement checksum of struct 
        public UInt16 Identifier;      // identifier 
        public UInt16 SequenceNumber;     // sequence number 
        public Byte[] Data; 

    } 
// class IcmpPacket 




2、执行ping命令

首先,我们用使用Process类,来创建独立的进程,导入System.Diagnostics,

using System.Diagnostics;

实例一个Process类,启动一个独立进程

Process p = new Process();

Process类有一个StartInfo属性,这个是ProcessStartInfo类,包括了一些属性和方法,

下面我们用到了他的几个属性:

设定程序名

p.StartInfo.FileName = "cmd.exe";

关闭Shell的使用

p.StartInfo.UseShellExecute = false;

重定向标准输入

p.StartInfo.RedirectStandardInput = true;

重定向标准输出

p.StartInfo.RedirectStandardOutput = true;

重定向错误输出

p.StartInfo.RedirectStandardError = true;

设置不显示窗口

p.StartInfo.CreateNoWindow = true;

上面几个属性的设置是比较关键的一步。

既然都设置好了那就启动进程吧,

p.Start();

输入要执行的命令,这里就是ping了,

p.StandardInput.WriteLine("ping -n 1 www.iwebtrados.com.cn");

p.StandardInput.WriteLine("exit");

从输出流获取命令执行结果,

string strRst = p.StandardOutput.ReadToEnd();

3、利用c#2.0新增的Ping类

这里我写的是一个窗体程序。首先添加textbox,listbox,button控件,其中textbox录入域名或IP,listbox显示结果.

在button1_click事件键入

 


private void button1_Click(object sender, EventArgs e) 

    Ping p1 
= new Ping(); //只是演示,没有做错误处理 

    PingReply reply = p1.Send(this.textBox1.Text);//阻塞方式 
    displayReply(reply); //显示结果 



private void displayReply(PingReply reply) //显示结果 

    StringBuilder sbuilder ; 
    
if (reply.Status ==
 IPStatus.Success) 
    { 
        sbuilder 
= new
 StringBuilder(); 
        sbuilder.Append(
string.Format("Address: {0} "
, reply.Address.ToString ())); 
        sbuilder.Append(
string.Format("RoundTrip time: {0} "
, reply.RoundtripTime)); 
        sbuilder.Append(
string.Format("Time to live: {0} "
, reply.Options.Ttl)); 
        sbuilder.Append(
string.Format("Don't fragment: {0} "
, reply.Options.DontFragment)); 
        sbuilder.Append(
string.Format("Buffer size: {0} "
, reply.Buffer.Length)); 
        listBox1.Items.Add(sbuilder.ToString()); 
    } 

}

也可以做异步的处理,修改button1_click,并添加PingCompletedCallBack方法

 


private void button1_Click(object sender, EventArgs e) 

    Ping p1 
= new
 Ping(); 
    p1.PingCompleted 
+= new PingCompletedEventHandler(this.PingCompletedCallBack);//设置PingCompleted事件处理程序 

    p1.SendAsync(this.textBox1.Text, null); 
}

private void PingCompletedCallBack(object
 sender, PingCompletedEventArgs e) 

    
if
 (e.Cancelled) 
    { 
        listBox1.Items.Add(
"Ping Canncel"
); 
        
return

    } 
    
if (e.Error != null

    { 
        listBox1.Items.Add(e.Error.Message); 
        
return


    } 
    StringBuilder sbuilder; 
    PingReply reply 
=
 e.Reply; 
    
if (reply.Status ==
 IPStatus.Success) 
    { 
        sbuilder 
= new
 StringBuilder(); 
        sbuilder.Append(
string.Format("Address: {0} "
, reply.Address.ToString())); 
        sbuilder.Append(
string.Format("RoundTrip time: {0} "
, reply.RoundtripTime)); 
        sbuilder.Append(
string.Format("Time to live: {0} "
, reply.Options.Ttl)); 
        sbuilder.Append(
string.Format("Don't fragment: {0} "
, reply.Options.DontFragment)); 
        sbuilder.Append(
string.Format("Buffer size: {0} "
, reply.Buffer.Length)); 
        listBox1.Items.Add(sbuilder.ToString()); 

    } 
}

怎么样,相比1、2方式,3是不是简单的多呀。

作者:网络小筑
个人主页:http://www.iwebtrados.com.cn/

posted @ 2009-08-18 21:04  oraclejava  阅读(519)  评论(0)    收藏  举报