核心代碼
public string DoSocketGet(string server)
{
Encoding ascii = Encoding.ASCII;
string request = $"GET / HTTP/1.1\r\nHost: {server}\r\nConnection: Close\r\n\r\n";
byte[] sendBytes = ascii.GetBytes(request);
byte[] recvBuffer = new byte[256];
string response = null;
// 解析 IP
IPAddress ip = Dns.GetHostAddresses(server)[0];
IPEndPoint endPoint = new IPEndPoint(ip, 80);
// 創建 TCP Socket
using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
socket.Connect(endPoint);
if (!socket.Connected)
return "Unable to connect to host";
// 發送請求
socket.Send(sendBytes, sendBytes.Length, SocketFlags.None);
// 接收響應循環
int bytes = socket.Receive(recvBuffer, recvBuffer.Length, SocketFlags.None);
response = $"Default HTML page on {server}:\r\n";
response += ascii.GetString(recvBuffer, 0, bytes);
while (bytes > 0)
{
bytes = socket.Receive(recvBuffer, recvBuffer.Length, SocketFlags.None);
response += ascii.GetString(recvBuffer, 0, bytes);
}
}
return response;
}
關鍵步驟解析
| 步驟 | API | 說明 |
| DNS 解析 | Dns.GetHostAddresses | 獲取域名對應 IP 列表,取第一個 |
| 端點構造 | IPEndPoint(ip, 80) | HTTP 默認端口 80 |
| Socket 創建 | new Socket(InterNetwork, Stream, Tcp) | IPv4、流式、TCP 協議 |
| 連接 | Connect(endPoint) | 三次握手建立連接 |
| 發送 | Send(byte[], int, SocketFlags) | 發送原始 HTTP 請求字節 |
| 接收循環 | Receive(byte[], int, SocketFlags) | 阻塞讀取直到連接關閉 (Connection: Close) |
HTTP 協議要點
- 請求行:
GET / HTTP/1.1
- Host 頭:HTTP/1.1 必須,支持虛擬主機
- Connection: Close:告知服務端響應後關閉連接,客戶端才能靠
Receive 返回 0 判斷結束
- 雙 CRLF (
\r\n\r\n) 結束請求頭
改進建議
- 使用
HttpWebRequest/HttpClient 替代手工 Socket(生產環境)
- 支持 HTTPS:需
SslStream 包裝 Socket 進行 TLS 握手
- 異步模式:
BeginSend/EndSend、BeginReceive/EndReceive 或 SendAsync/ReceiveAsync
- 完整響應解析:分離狀態行、頭部、實體體,處理 Chunked、Content-Length、Gzip 等
- 緩衝區動態擴展:
List 或 MemoryStream 避免固定 256 字節截斷
錯誤處理
try
{
// ... socket operations
}
catch (SocketException ex) when (ex.SocketErrorCode == SocketError.ConnectionRefused)
{
return "Connection refused";
}
catch (SocketException ex)
{
return $"Socket error: {ex.Message}";
}
catch (Exception ex)
{
return $"General error: {ex.Message}";
}