以下為完整事件處理程式碼 (已修正大小寫與語法),逐段解析關鍵步驟:
private void button1_Click(object sender, EventArgs e)
{
listBox1.Items.Clear();
string hostName = textBox1.Text;
for (int k = 0; k < 3; k++) // 發送 3 次
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp);
IPHostEntry hostInfo;
try { hostInfo = Dns.GetHostEntry(hostName); }
catch { listBox1.Items.Add("找不到此主機!"); return; }
IPEndPoint remoteEP = new IPEndPoint(hostInfo.AddressList[0], 30); // 任意埠號 30
IPHostEntry localInfo = Dns.GetHostEntry(Dns.GetHostName());
IPEndPoint localEP = new IPEndPoint(localInfo.AddressList[0], 30);
const int ICMP_ECHO = 8;
int dataSize = 4;
int packetSize = dataSize + 8; // ICMP 標頭 8 bytes
IcmpPacket packet = new IcmpPacket(ICMP_ECHO, 0, 0, 45, 0, dataSize);
byte[] buffer = new byte[packetSize];
int index = packet.CountByte(buffer);
if (index != packetSize) { listBox1.Items.Add("封包組裝錯誤!"); return; }
// 計算檢驗和
int cksumBufLen = (int)Math.Ceiling((double)index / 2);
ushort[] cksumBuffer = new ushort[cksumBufLen];
int offset = 0;
for (int i = 0; i < cksumBufLen; i++)
{
cksumBuffer[i] = BitConverter.ToUInt16(buffer, offset);
offset += 2;
}
packet.CheckSum = IcmpPacket.SumOfCheck(cksumBuffer);
// 重新序列化含正確檢驗和的封包
byte[] sendData = new byte[packetSize];
index = packet.CountByte(sendData);
if (index != packetSize) { listBox1.Items.Add("封包組裝錯誤!"); return; }
int startTime = Environment.TickCount;
if (socket.SendTo(sendData, packetSize, SocketFlags.None, remoteEP) == -1)
{ listBox1.Items.Add("無法傳送封包!"); }
byte[] recvBuffer = new byte[256];
EndPoint senderEP = localEP;
int timeout = 0;
while (true)
{
int nBytes = socket.ReceiveFrom(recvBuffer, 256, SocketFlags.None, ref senderEP);
if (nBytes == -1) { listBox1.Items.Add("主機無回應!"); break; }
if (nBytes > 0)
{
int elapsed = Environment.TickCount - startTime;
listBox1.Items.Add($"Reply from {hostInfo.AddressList[0]}: time={elapsed}ms bytes={nBytes}");
break;
}
timeout = Environment.TickCount - startTime;
if (timeout > 1000) { listBox1.Items.Add("Request timed out."); break; }
}
socket.Close();
}
}
SocketType.Raw 會擲出 SocketException (存取被拒)。IPEndPoint 建構式需填入,任何未衝突數值皆可。