Bạn muốn kiểm tra một máy tính có online hay không và đo thời gian đáp ứng (response time) của nó.
Gửi một thông điệp “ping”. Thông điệp này được gửi bằng giao thức Internet Control Message Protocol (ICMP) với một raw-socket.
Một thông điệp “ping” giao tiếp với một thiết bị tại một địa chỉ IP cụ thể, gửi một thông điệp thử nghiệm, và yêu cầu thiết bị này đáp ứng lại. Để đo thời gian kết nối giữa hai máy tính, bạn có thể đo thời gian cho một đáp ứng.
Mặc dù thông điệp “ping” đơn giản hơn các kiểu giao tiếp khác, nhưng hiện thực một tiện ích “ping” trong .NET đòi hỏi một lượng lớn mã lệnh networking mức-thấp và phức tạp. Thư viện lớp .NET không có sẵn giải pháp nào—thay vào đó, bạn phải sử dụng raw-socket và một số mã lệnh cực kỳ dài.
Tuy nhiên, đã có ít nhất một nhà phát triển giải quyết được vấn đề “ping”. Dưới đây là mã lệnh do Lance Olson, một nhà phát triển của Microsoft, cung cấp. Mã lệnh này cho phép “ping” một host bằng tên hay địa chỉ IP và đo lượng mili-giây cho một đáp ứng.
using System; using System.Net;using System.Net.Sockets;public class Pinger { public static int GetPingTime(string host) { int dwStart = 0, dwStop = 0; // Tạo một raw-socket. Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp); // Lấy IPEndPoint của server, và chuyển nó thành EndPoint. IPHostEntry serverHE = Dns.GetHostByName(host); IPEndPoint ipepServer = new IPEndPoint(serverHE.AddressList[0], 0); EndPoint epServer = (ipepServer); // Thiết lập endpoint cho máy client. IPHostEntry fromHE = Dns.GetHostByName(Dns.GetHostName()); IPEndPoint ipEndPointFrom = new IPEndPoint(fromHE.AddressList[0], 0); EndPoint EndPointFrom = (ipEndPointFrom); // Tạo packet. int PacketSize = 0; IcmpPacket packet = new IcmpPacket(); for (int j = 0; j < 1; j++) { packet.Type = ICMP_ECHO; packet.SubCode = 0; packet.CheckSum = UInt16.Parse("0"); packet.Identifier = UInt16.Parse("45"); packet.SequenceNumber = UInt16.Parse("0"); int PingData = 32; packet.Data = new Byte[PingData]; for (int i = 0; i < PingData; i++) packet.Data = (byte)'#'; PacketSize = PingData + 8; Byte [] icmp_pkt_buffer = new Byte [PacketSize]; int index = 0; index = Serialize(packet, icmp_pkt_buffer, PacketSize, PingData); // Tính checksum cho packet. double double_length = Convert.ToDouble(index); double dtemp = Math.Ceiling(double_length / 2); int cksum_buffer_length = Convert.ToInt32(dtemp); UInt16[] cksum_buffer = new UInt16[cksum_buffer_length]; int icmp_header_buffer_index = 0; for (int i = 0; i < cksum_buffer_length; i++) { cksum_buffer = BitConverter.ToUInt16(icmp_pkt_buffer, icmp_header_buffer_index); icmp_header_buffer_index += 2; } UInt16 u_cksum = checksum(cksum_buffer, cksum_buffer_length); packet.CheckSum = u_cksum; // Tuần tự hóa packet. byte[] sendbuf = new byte[PacketSize]; index = Serialize(packet, sendbuf, PacketSize, PingData); // Bắt đầu tính giờ. dwStart = System.Environment.TickCount; socket.SendTo(sendbuf, PacketSize, 0, epServer); // Nhận đáp ứng, và ngừng tính giờ. byte[] ReceiveBuffer = new byte[256]; socket.ReceiveFrom(ReceiveBuffer, 256, 0, ref EndPointFrom); dwStop = System.Environment.TickCount - dwStart; } // Dọn dẹp và trả về thời gian "ping" (tính theo giây). socket.Close(); return (int)dwStop; } private static int Serialize(IcmpPacket packet, byte[] buffer, int packetSize, int pingData) { // (Bỏ qua phương thức private dùng để tuần tự hóa packet.) } private static UInt16 checksum(UInt16[] buffer, int size) { // (Bỏ qua phương thức private dùng để tính checksum.) } }public class IcmpPacket { public byte Type; public byte SubCode; public UInt16 CheckSum; public UInt16 Identifier; public UInt16 SequenceNumber; public byte[] Data;}
Bạn có thể sử dụng phương thức tĩnh Pinger.GetPingTime với một địa chỉ IP hay một tên miền. Phương thức GetPingTime trả về lượng mili-giây trôi qua trước khi một đáp ứng được tiếp nhận. Dưới đây là đoạn mã thử nghiệm trên ba website:
public class PingTest { private static void Main() { Console.WriteLine("Milliseconds to contact www.yahoo.com:" + Pinger.GetPingTime("www.yahoo.com").ToString()); Console.WriteLine("Milliseconds to contact www.seti.org:" + Pinger.GetPingTime("www.seti.org").ToString()); Console.WriteLine("Milliseconds to contact the local computer:" + Pinger.GetPingTime("127.0.0.1").ToString()); Console.ReadLine(); }}
Thử nghiệm “ping” cho phép bạn xác minh các máy tính khác có online hay không. Nó cũng có thể hữu ích khi ứng dụng của bạn cần đánh giá những máy tính khác nhau (ở xa) nhưng cho cùng nội dung để xác định máy nào có thời gian giao tiếp mạng thấp nhất.
Một yêu cầu “ping” có thể không thành công nếu bị firewall ngăn lại. Ví dụ, nhiều site bỏ qua yêu cầu “ping” vì sợ bị sa vào một luồng “ping” cùng một lúc sẽ làm cản trở server (thực chất là một tấn công từ chối dịch vụ).
Trích từ “Các giải pháp lập trình C#”
Gửi một thông điệp “ping”. Thông điệp này được gửi bằng giao thức Internet Control Message Protocol (ICMP) với một raw-socket.
Một thông điệp “ping” giao tiếp với một thiết bị tại một địa chỉ IP cụ thể, gửi một thông điệp thử nghiệm, và yêu cầu thiết bị này đáp ứng lại. Để đo thời gian kết nối giữa hai máy tính, bạn có thể đo thời gian cho một đáp ứng.
Mặc dù thông điệp “ping” đơn giản hơn các kiểu giao tiếp khác, nhưng hiện thực một tiện ích “ping” trong .NET đòi hỏi một lượng lớn mã lệnh networking mức-thấp và phức tạp. Thư viện lớp .NET không có sẵn giải pháp nào—thay vào đó, bạn phải sử dụng raw-socket và một số mã lệnh cực kỳ dài.
Tuy nhiên, đã có ít nhất một nhà phát triển giải quyết được vấn đề “ping”. Dưới đây là mã lệnh do Lance Olson, một nhà phát triển của Microsoft, cung cấp. Mã lệnh này cho phép “ping” một host bằng tên hay địa chỉ IP và đo lượng mili-giây cho một đáp ứng.
using System; using System.Net;using System.Net.Sockets;public class Pinger { public static int GetPingTime(string host) { int dwStart = 0, dwStop = 0; // Tạo một raw-socket. Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp); // Lấy IPEndPoint của server, và chuyển nó thành EndPoint. IPHostEntry serverHE = Dns.GetHostByName(host); IPEndPoint ipepServer = new IPEndPoint(serverHE.AddressList[0], 0); EndPoint epServer = (ipepServer); // Thiết lập endpoint cho máy client. IPHostEntry fromHE = Dns.GetHostByName(Dns.GetHostName()); IPEndPoint ipEndPointFrom = new IPEndPoint(fromHE.AddressList[0], 0); EndPoint EndPointFrom = (ipEndPointFrom); // Tạo packet. int PacketSize = 0; IcmpPacket packet = new IcmpPacket(); for (int j = 0; j < 1; j++) { packet.Type = ICMP_ECHO; packet.SubCode = 0; packet.CheckSum = UInt16.Parse("0"); packet.Identifier = UInt16.Parse("45"); packet.SequenceNumber = UInt16.Parse("0"); int PingData = 32; packet.Data = new Byte[PingData]; for (int i = 0; i < PingData; i++) packet.Data = (byte)'#'; PacketSize = PingData + 8; Byte [] icmp_pkt_buffer = new Byte [PacketSize]; int index = 0; index = Serialize(packet, icmp_pkt_buffer, PacketSize, PingData); // Tính checksum cho packet. double double_length = Convert.ToDouble(index); double dtemp = Math.Ceiling(double_length / 2); int cksum_buffer_length = Convert.ToInt32(dtemp); UInt16[] cksum_buffer = new UInt16[cksum_buffer_length]; int icmp_header_buffer_index = 0; for (int i = 0; i < cksum_buffer_length; i++) { cksum_buffer = BitConverter.ToUInt16(icmp_pkt_buffer, icmp_header_buffer_index); icmp_header_buffer_index += 2; } UInt16 u_cksum = checksum(cksum_buffer, cksum_buffer_length); packet.CheckSum = u_cksum; // Tuần tự hóa packet. byte[] sendbuf = new byte[PacketSize]; index = Serialize(packet, sendbuf, PacketSize, PingData); // Bắt đầu tính giờ. dwStart = System.Environment.TickCount; socket.SendTo(sendbuf, PacketSize, 0, epServer); // Nhận đáp ứng, và ngừng tính giờ. byte[] ReceiveBuffer = new byte[256]; socket.ReceiveFrom(ReceiveBuffer, 256, 0, ref EndPointFrom); dwStop = System.Environment.TickCount - dwStart; } // Dọn dẹp và trả về thời gian "ping" (tính theo giây). socket.Close(); return (int)dwStop; } private static int Serialize(IcmpPacket packet, byte[] buffer, int packetSize, int pingData) { // (Bỏ qua phương thức private dùng để tuần tự hóa packet.) } private static UInt16 checksum(UInt16[] buffer, int size) { // (Bỏ qua phương thức private dùng để tính checksum.) } }public class IcmpPacket { public byte Type; public byte SubCode; public UInt16 CheckSum; public UInt16 Identifier; public UInt16 SequenceNumber; public byte[] Data;}
Bạn có thể sử dụng phương thức tĩnh Pinger.GetPingTime với một địa chỉ IP hay một tên miền. Phương thức GetPingTime trả về lượng mili-giây trôi qua trước khi một đáp ứng được tiếp nhận. Dưới đây là đoạn mã thử nghiệm trên ba website:
public class PingTest { private static void Main() { Console.WriteLine("Milliseconds to contact www.yahoo.com:" + Pinger.GetPingTime("www.yahoo.com").ToString()); Console.WriteLine("Milliseconds to contact www.seti.org:" + Pinger.GetPingTime("www.seti.org").ToString()); Console.WriteLine("Milliseconds to contact the local computer:" + Pinger.GetPingTime("127.0.0.1").ToString()); Console.ReadLine(); }}
Thử nghiệm “ping” cho phép bạn xác minh các máy tính khác có online hay không. Nó cũng có thể hữu ích khi ứng dụng của bạn cần đánh giá những máy tính khác nhau (ở xa) nhưng cho cùng nội dung để xác định máy nào có thời gian giao tiếp mạng thấp nhất.
Một yêu cầu “ping” có thể không thành công nếu bị firewall ngăn lại. Ví dụ, nhiều site bỏ qua yêu cầu “ping” vì sợ bị sa vào một luồng “ping” cùng một lúc sẽ làm cản trở server (thực chất là một tấn công từ chối dịch vụ).
Trích từ “Các giải pháp lập trình C#”