C#中的UDP ping实现

时间:2014-05-13 07:54:22

标签: c# .net networking udp ping

我尝试使用C#实现基于udp数据包的ping。我们的想法是将udp数据包发送到错误的端口并获取ICMP数据包,以防止端口无法访问错误。并且,在发送udp数据包和接收icmp数据包之间经过的时间是ping时间。我这样做:

    // Start building the headers
    //Console.WriteLine("Building the packet header...");
    int messageSize = 64;
    byte[] builtPacket, payLoad = new byte[messageSize];
    UdpHeader udpPacket = new UdpHeader();
    ArrayList headerList = new ArrayList();
    Socket rawSocket = null;
    SocketOptionLevel socketLevel;

    // Initialize the payload
    //Console.WriteLine("Initialize the payload...");
    for (int i = 0; i < payLoad.Length; i++)
        payLoad[i] = (byte)'0';

    // Fill out the UDP header first
    //Console.WriteLine("Filling out the UDP header...");
    udpPacket.SourcePort = 33434;
    udpPacket.DestinationPort = 33434;
    udpPacket.Length = (ushort)(UdpHeader.UdpHeaderLength + messageSize);
    udpPacket.Checksum = 0;

    Ipv4Header ipv4Packet = new Ipv4Header();

    // Build the IPv4 header
    //Console.WriteLine("Building the IPv4 header...");
    ipv4Packet.Version = 4;
    ipv4Packet.Protocol = (byte)ProtocolType.Udp;
    ipv4Packet.Ttl = 30;
    ipv4Packet.Offset = 0;
    ipv4Packet.Length = (byte)Ipv4Header.Ipv4HeaderLength;
    ipv4Packet.TotalLength = (ushort)Convert.ToUInt16(Ipv4Header.Ipv4HeaderLength + UdpHeader.UdpHeaderLength + messageSize);
    ipv4Packet.SourceAddress = sourceAddress;
    ipv4Packet.DestinationAddress = destAddress;

    // Set the IPv4 header in the UDP header since it is required to calculate the
    //    pseudo header checksum
    //Console.WriteLine("Setting the IPv4 header for pseudo header checksum...");
    udpPacket.ipv4PacketHeader = ipv4Packet;

    // Add IPv4 header to list of headers -- headers should be added in th order
    //    they appear in the packet (i.e. IP first then UDP)
    //Console.WriteLine("Adding the IPv4 header to the list of header, encapsulating packet...");
    headerList.Add(ipv4Packet);
    socketLevel = SocketOptionLevel.IP;

    // Add the UDP header to list of headers after the IP header has been added
    //Console.WriteLine("Adding the UDP header to the list of header, after IP header...");
    headerList.Add(udpPacket);

    // Convert the header classes into the binary on-the-wire representation
    //Console.WriteLine("Converting the header classes into the binary...");
    builtPacket = udpPacket.BuildPacket(headerList, payLoad);

    // Create the raw socket for this packet
    //Console.WriteLine("Creating the raw socket using Socket()...");
    rawSocket = new Socket(sourceAddress.AddressFamily, SocketType.Raw, ProtocolType.Udp);

    // Bind the socket to the interface specified
    //Console.WriteLine("Binding the socket to the specified interface using Bind()...");
    IPAddress bindAddress = IPAddress.Any;
    rawSocket.Bind(new IPEndPoint(bindAddress, 0));

    // Set the HeaderIncluded option since we include the IP header
    //Console.WriteLine("Setting the HeaderIncluded option for IP header...");
    rawSocket.SetSocketOption(socketLevel, SocketOptionName.HeaderIncluded, 1);
    rawSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 1000);

    Stopwatch timer = new Stopwatch();

    try {
        for (int i = 0; i < 5; i++) {
            timer.Reset();

            timer.Start();

            int rc = rawSocket.SendTo(builtPacket, new IPEndPoint(destAddress, 0));
            Console.WriteLine("Sent {0} bytes to {1}", rc, destAddress);

            Socket icmpListener = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp);
            icmpListener.Bind(new IPEndPoint(sourceAddress, 0));
            icmpListener.IOControl(IOControlCode.ReceiveAll, new byte[] { 1, 0, 0, 0 }, new byte[] { 1, 0, 0, 0 });
            icmpListener.Shutdown(SocketShutdown.Send);

            byte[] buffer = new byte[4096];
            EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);

            try {
                int bytesRead = icmpListener.ReceiveFrom(buffer, ref remoteEndPoint);
                timer.Stop();
                Console.WriteLine("Recieved " + bytesRead + " bytes from " + destAddress + " in " + timer.ElapsedMilliseconds + "ms\n");
            }
            catch {
                Console.WriteLine("Server is not responding!");
            }
            finally {
                icmpListener.Close();
            }
        }

    }
    catch (SocketException err) {
        Console.WriteLine("Socket error occurred: {0}", err.Message);
    }
    finally {
        rawSocket.Close();
    }

它不时有效。问题是有些网站发给我一个icmp数据包而有些没有。实际上起初他们也没有发送然后我用Windows ping ping它们并跟踪traceroute它们。并改变了端口号,它起作用了。但并不适合所有人。我只能ping google.com和另外一个网站,但其他人不会发回icmp数据包。与我尝试ping的本地网络计算机相同的情况。我发送了udp数据包,但没有得到icmp。

我用wireshark来观看飞行的数据包。

我在这里做错了什么?

0 个答案:

没有答案