用 C# 自己動手編寫一個 Web 服務器
在.NET世界中,C#是一種功能強大的編程語言,常被用于構建各種類型的應用程序,包括Web服務器。雖然在實際生產環境中,我們通常會使用成熟的Web服務器軟件(如IIS、Kestrel等),但了解如何用C#從頭開始構建一個簡單的Web服務器,對于深入理解HTTP協議和網絡編程是非常有價值的。
本文將指導你使用C#編寫一個簡單的Web服務器,并包含具體的代碼實現。
第一步:理解HTTP協議
在編寫Web服務器之前,我們需要對HTTP協議有一個基本的了解。HTTP是一種無狀態的、基于請求和響應的協議。客戶端(如Web瀏覽器)發送HTTP請求到服務器,服務器處理請求并返回HTTP響應。
HTTP請求由請求行、請求頭部和請求體組成。請求行包含請求方法(GET、POST等)、請求URL和HTTP協議版本。請求頭部包含關于請求的附加信息,如Host、User-Agent等。請求體包含實際發送給服務器的數據,通常用于POST請求。
HTTP響應由狀態行、響應頭部和響應體組成。狀態行包含HTTP協議版本、狀態碼和狀態消息。響應頭部包含關于響應的附加信息,如Content-Type、Content-Length等。響應體包含服務器返回給客戶端的實際數據。
第二步:創建TCP監聽器
在C#中,我們可以使用TcpListener類來創建一個TCP監聽器,用于監聽傳入的HTTP請求。以下是一個簡單的示例代碼,展示如何創建TCP監聽器并等待連接:
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
class SimpleWebServer
{
private const int Port = 8080;
public static void Main()
{
TcpListener listener = new TcpListener(IPAddress.Any, Port);
listener.Start();
Console.WriteLine($"Server started at http://localhost:{Port}/");
while (true)
{
TcpClient client = listener.AcceptTcpClient();
HandleClientAsync(client).Wait();
}
}
private static async Task HandleClientAsync(TcpClient client)
{
NetworkStream stream = client.GetStream();
StreamReader reader = new StreamReader(stream, Encoding.UTF8);
StreamWriter writer = new StreamWriter(stream, Encoding.UTF8) { AutoFlush = true };
try
{
// 讀取請求行
string requestLine = await reader.ReadLineAsync();
if (string.IsNullOrEmpty(requestLine))
return;
Console.WriteLine($"Received request: {requestLine}");
// 解析請求行(為了簡化,這里只處理GET請求)
string[] parts = requestLine.Split(' ');
if (parts.Length != 3 || parts[0] != "GET")
{
SendErrorResponse(writer, 400, "Bad Request");
return;
}
string path = parts[1];
if (path != "/")
{
SendErrorResponse(writer, 404, "Not Found");
return;
}
// 發送響應
SendResponse(writer, 200, "OK", "<html><body><h1>Hello, World!</h1></body></html>");
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
SendErrorResponse(writer, 500, "Internal Server Error");
}
finally
{
client.Close();
}
}
private static void SendResponse(StreamWriter writer, int statusCode, string statusMessage, string content)
{
writer.WriteLine($"HTTP/1.1 {statusCode} {statusMessage}");
writer.WriteLine("Content-Type: text/html; charset=UTF-8");
writer.WriteLine($"Content-Length: {content.Length}");
writer.WriteLine();
writer.Write(content);
}
private static void SendErrorResponse(StreamWriter writer, int statusCode, string statusMessage)
{
string content = $"<html><body><h1>{statusCode} {statusMessage}</h1></body></html>";
SendResponse(writer, statusCode, statusMessage, content);
}
}
這個示例代碼創建了一個簡單的Web服務器,監聽8080端口。當客戶端連接到服務器時,服務器會讀取請求行,并根據請求路徑返回相應的響應。