博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

c#下实现ping操作

Posted on 2010-08-27 09:52  linFen  阅读(26122)  评论(6编辑  收藏  举报

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()); 

    } 
}