首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 實現簡易 HTTP Web 服務器(二):完整代碼實現

     編輯:關於C語言

核心類:MyWebServer


using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace Cnnbsun.WebServer
{
    public class MyWebServer
    {
        private TcpListener listener;
        private readonly int port = 8080;
        private readonly string webRoot = @"E:\MyWebServerRoot\"; // 虛擬目錄

        public MyWebServer()
        {
            try
            {
                listener = new TcpListener(port);
                listener.Start();
                Console.WriteLine("Web Server Running... Press ^C to Stop...");
                new Thread(StartListen) { IsBackground = true }.Start();
            }
            catch (Exception ex) { Console.WriteLine("啟動失敗: " + ex); }
        }

        void StartListen()
        {
            while (true)
            {
                Socket socket = listener.AcceptSocket();
                if (!socket.Connected) continue;

                Console.WriteLine($"\nClient Connected: {socket.RemoteEndPoint}");
                byte[] buffer = new byte[1024];
                int received = socket.Receive(buffer);
                string request = Encoding.ASCII.GetString(buffer, 0, received);

                // 僅處理 GET
                if (!request.StartsWith("GET"))
                {
                    Console.WriteLine("僅支持 GET");
                    socket.Close(); continue;
                }

                // 解析請求行:GET /path/file HTTP/1.0
                int httpIdx = request.IndexOf("HTTP", 1);
                string httpVer = request.Substring(httpIdx, 8);
                string reqLine = request.Substring(0, httpIdx - 1).Replace("\\", "/");

                // 目錄補全
                if (reqLine.IndexOf('.') < 0 && !reqLine.EndsWith("/")) reqLine += "/";

                // 提取文件名
                int lastSlash = reqLine.LastIndexOf('/') + 1;
                string fileName = reqLine.Substring(lastSlash);
                if (string.IsNullOrEmpty(fileName)) fileName = "index.html";

                // 物理路徑
                string physicalPath = Path.Combine(webRoot, fileName);
                Console.WriteLine($"Request: {physicalPath}");

                // 響應
                if (!File.Exists(physicalPath))
                {
                    SendError(socket, httpVer, "404 Not Found", "

404 File Not Found

"); } else { byte[] fileBytes = File.ReadAllBytes(physicalPath); SendResponse(socket, httpVer, "text/html", fileBytes, "200 OK"); } socket.Close(); } } void SendResponse(Socket s, string httpVer, string mime, byte[] body, string status) { string header = $"{httpVer} {status}\r\n" + $"Server: CustomCSharpServer\r\n" + $"Content-Type: {mime}\r\n" + $"Content-Length: {body.Length}\r\n\r\n"; byte[] headerBytes = Encoding.ASCII.GetBytes(header); s.Send(headerBytes); s.Send(body); } void SendError(Socket s, string httpVer, string status, string html) { byte[] body = Encoding.ASCII.GetBytes(html); SendResponse(s, httpVer, "text/html", body, status); } public static void Main() => new MyWebServer(); } }

關鍵點解析

  1. TcpListener:阻塞式監聽端口,AcceptSocket 返回已連接 Socket。
  2. 請求解析:簡易字符串解析,提取方法、路徑、HTTP 版本。
  3. 靜態文件服務:讀取文件字節 → 發送 HTTP 頭 + 體。
  4. 線程模型:單線程循環處理,高併發下會阻塞。生產環境需改用 ThreadPool、async/await 或 Kestrel。
  5. 安全性:路徑遍歷風險(../../etc/passwd),需規範化路徑並限制在 webRoot 內。

編譯與測試


csc webserver.cs
webserver.exe
// 瀏覽器訪問 https://localhost:8080/index.html

擴展方向

  • 支持 POST、HEAD、PUT 等方法。
  • MIME 類型映射表(.css→text/css 等)。
  • 目錄瀏覽、默認文檔列表。
  • HTTPS (TLS) 支持:SslStream 包裝 Socket。
  • 配置文件驅動端口、根目錄、日誌級別。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved