位置: 文档库 > C#(.NET) > 文档下载预览

《C#实现一个最简单的HTTP服务器.doc》

1. 下载的文档为doc格式,下载后可用word或者wps进行编辑;

2. 将本文以doc文档格式下载到电脑,方便收藏和打印;

3. 下载后的文档,内容与下面显示的完全一致,下载之前请确认下面内容是否您想要的,是否完整.

点击下载文档

C#实现一个最简单的HTTP服务器.doc

《C#实现一个最简单的HTTP服务器》

在.NET生态中,HTTP服务器的开发通常依赖ASP.NET Core框架,但若需要快速实现一个轻量级的HTTP服务器(例如用于测试、工具开发或嵌入式场景),可以通过C#的`HttpListener`类直接操作底层HTTP协议。本文将通过一个完整的示例,演示如何用最少的代码构建一个可响应GET/POST请求的HTTP服务器,并深入解析其工作原理。

一、HttpListener基础

`HttpListener`是.NET Framework和.NET Core中提供的底层HTTP监听器,位于`System.Net`命名空间。它允许开发者直接监听指定URL前缀(如`http://localhost:8080/`)的HTTP请求,无需配置IIS或Kestrel等完整Web服务器。

核心步骤:

  1. 创建`HttpListener`实例并配置监听前缀
  2. 启动监听(`Start()`方法)
  3. 进入异步等待循环(`GetContextAsync()`)
  4. 处理请求上下文(`HttpListenerContext`)
  5. 返回响应(`HttpListenerResponse`)

二、完整代码实现

以下是一个支持GET/POST请求的最小化HTTP服务器实现,包含HTML表单处理和JSON响应:

using System;
using System.Net;
using System.Text;
using System.Threading.Tasks;

class SimpleHttpServer
{
    private readonly HttpListener _listener = new HttpListener();
    private readonly string _urlPrefix;

    public SimpleHttpServer(string urlPrefix = "http://localhost:8080/")
    {
        _urlPrefix = urlPrefix;
    }

    public async Task StartAsync()
    {
        _listener.Prefixes.Add(_urlPrefix);
        _listener.Start();
        Console.WriteLine($"Server started at {_urlPrefix}");

        try
        {
            while (true)
            {
                var context = await _listener.GetContextAsync();
                _ = HandleRequestAsync(context); // 非阻塞处理
            }
        }
        catch (HttpListenerException ex)
        {
            Console.WriteLine($"Listener error: {ex.Message}");
        }
        finally
        {
            _listener.Stop();
        }
    }

    private async Task HandleRequestAsync(HttpListenerContext context)
    {
        var request = context.Request;
        var response = context.Response;

        try
        {
            // 根据请求方法处理
            if (request.HttpMethod == "GET")
            {
                await HandleGetRequest(response);
            }
            else if (request.HttpMethod == "POST")
            {
                await HandlePostRequest(request, response);
            }
            else
            {
                SendErrorResponse(response, HttpStatusCode.MethodNotAllowed, "Method not allowed");
            }
        }
        catch (Exception ex)
        {
            SendErrorResponse(response, HttpStatusCode.InternalServerError, ex.Message);
        }
        finally
        {
            response.Close();
        }
    }

    private async Task HandleGetRequest(HttpListenerResponse response)
    {
        var html = @"



Simple HTTP Server

    

Welcome to Simple HTTP Server

"; var buffer = Encoding.UTF8.GetBytes(html); response.ContentType = "text/html"; response.ContentLength64 = buffer.Length; await response.OutputStream.WriteAsync(buffer, 0, buffer.Length); } private async Task HandlePostRequest(HttpListenerRequest request, HttpListenerResponse response) { // 读取POST数据 string postData; using (var reader = new System.IO.StreamReader(request.InputStream, request.ContentEncoding)) { postData = await reader.ReadToEndAsync(); } // 简单解析表单数据(实际应用中应使用更健壮的解析器) var message = "No message received"; if (!string.IsNullOrEmpty(postData)) { var pairs = postData.Split('&'); foreach (var pair in pairs) { var kv = pair.Split('='); if (kv.Length == 2 && kv[0] == "message") { message = System.Web.HttpUtility.UrlDecode(kv[1]); break; } } } // 返回JSON响应 var jsonResponse = $"{{\"status\":\"success\",\"message\":\"{message}\"}}"; var buffer = Encoding.UTF8.GetBytes(jsonResponse); response.ContentType = "application/json"; response.ContentLength64 = buffer.Length; await response.OutputStream.WriteAsync(buffer, 0, buffer.Length); } private void SendErrorResponse(HttpListenerResponse response, HttpStatusCode statusCode, string message) { var errorResponse = $"{{\"error\":\"{message}\",\"code\":{(int)statusCode}}}"; var buffer = Encoding.UTF8.GetBytes(errorResponse); response.StatusCode = (int)statusCode; response.ContentType = "application/json"; response.ContentLength64 = buffer.Length; response.OutputStream.Write(buffer, 0, buffer.Length); } public void Stop() { _listener.Stop(); _listener.Close(); } } // 使用示例 class Program { static async Task Main(string[] args) { var server = new SimpleHttpServer(); var startTask = server.StartAsync(); Console.WriteLine("Press any key to stop..."); Console.ReadKey(); server.Stop(); await startTask; } }

三、代码解析

1. 监听配置

`HttpListener`通过`Prefixes`集合配置监听地址,支持:

  • `http://+:8080/` - 监听所有网络接口的8080端口
  • `http://localhost/` - 仅本地回环地址
  • `http://192.168.1.100:80/` - 指定IP和端口

注意:在非管理员权限下运行可能需要配置URL保留(通过`netsh http add urlacl`命令)。

2. 请求处理流程

`GetContextAsync()`会阻塞直到收到请求,返回的`HttpListenerContext`包含:

  • `Request`对象:包含方法、URL、头部、查询字符串、输入流等
  • `Response`对象:用于设置状态码、头部、输出流等

3. 异步处理优化

示例中使用`_ = HandleRequestAsync(context)`启动非阻塞处理,避免阻塞监听循环。实际生产环境中可能需要:

  • 限制并发请求数
  • 添加请求超时控制
  • 使用`SemaphoreSlim`进行流量控制

4. 内容类型处理

示例演示了三种内容类型:

  • HTML(`text/html`)
  • JSON(`application/json`)
  • 错误响应(自定义JSON结构)

四、扩展功能建议

1. 路由系统

当前实现是硬编码处理,可扩展为基于路径的路由:

private Dictionary> _routes = 
    new Dictionary>
{
    ["/api/data"] = HandleApiRequest,
    ["/"] = HandleRootRequest
};

2. 中间件支持

模拟ASP.NET Core的中间件管道:

public class MiddlewarePipeline
{
    private readonly List, Task>> _middlewares = new();

    public void Use(Func, Task> middleware)
    {
        _middlewares.Add(middleware);
    }

    public async Task Invoke(HttpListenerContext context)
    {
        var index = 0;
        async Task Next()
        {
            if (index 

3. 静态文件服务

添加静态文件支持(需处理MIME类型映射):

private async Task ServeStaticFile(HttpListenerContext context, string filePath)
{
    if (!File.Exists(filePath))
    {
        SendErrorResponse(context.Response, HttpStatusCode.NotFound, "File not found");
        return;
    }

    var extension = Path.GetExtension(filePath).ToLower();
    var mimeType = extension switch
    {
        ".html" => "text/html",
        ".css" => "text/css",
        ".js" => "application/javascript",
        ".jpg" or ".jpeg" => "image/jpeg",
        ".png" => "image/png",
        _ => "application/octet-stream"
    };

    var fileBytes = await File.ReadAllBytesAsync(filePath);
    context.Response.ContentType = mimeType;
    context.Response.ContentLength64 = fileBytes.Length;
    await context.Response.OutputStream.WriteAsync(fileBytes, 0, fileBytes.Length);
}

五、性能优化方向

1. 连接复用:默认情况下`HttpListener`会为每个请求创建新连接,可通过`Keep-Alive`头部优化

2. 缓冲区管理:重用`byte[]`缓冲区减少GC压力

3. 异步IO优化:使用`PipeReader`/`PipeWriter`(.NET Core 3.0+)处理流数据

4. 压缩支持:动态压缩响应内容(需处理`Accept-Encoding`头部)

六、安全注意事项

1. 输入验证:对所有用户输入进行严格验证(特别是POST数据)

2. HTTPS支持:通过`netsh http add sslcert`配置SSL证书

3. 请求大小限制:防止内存耗尽攻击

4. CORS策略:明确设置`Access-Control-Allow-Origin`头部

七、与ASP.NET Core对比

特性 HttpListener ASP.NET Core
依赖项 仅System.Net 需要完整框架
性能 较低(无中间件优化) 高性能(Kestrel优化)
功能 基础HTTP处理 路由、依赖注入、MVC等
适用场景 工具开发、测试、嵌入式 生产级Web应用

八、完整示例改进版

以下是添加路由和静态文件支持的增强版:

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;

public class EnhancedHttpServer
{
    private readonly HttpListener _listener = new HttpListener();
    private readonly Dictionary> _routes = 
        new Dictionary>(StringComparer.OrdinalIgnoreCase);
    private readonly string _staticFilesPath;

    public EnhancedHttpServer(string urlPrefix = "http://localhost:8080/", string staticFilesPath = null)
    {
        _listener.Prefixes.Add(urlPrefix);
        _staticFilesPath = staticFilesPath;
        
        // 默认路由
        _routes["/"] = HandleRoot;
        _routes["/api/echo"] = HandleEchoApi;
    }

    public void AddRoute(string path, Func handler)
    {
        _routes[path] = handler;
    }

    public async Task StartAsync()
    {
        _listener.Start();
        Console.WriteLine($"Server started at {_listener.Prefixes[0]}");

        try
        {
            while (true)
            {
                var context = await _listener.GetContextAsync();
                _ = ProcessRequestAsync(context);
            }
        }
        catch (HttpListenerException ex)
        {
            Console.WriteLine($"Listener error: {ex.Message}");
        }
        finally
        {
            _listener.Stop();
        }
    }

    private async Task ProcessRequestAsync(HttpListenerContext context)
    {
        var request = context.Request;
        var response = context.Response;

        try
        {
            // 检查静态文件
            if (_staticFilesPath != null && request.HttpMethod == "GET")
            {
                var filePath = Path.Combine(_staticFilesPath, request.Url.AbsolutePath.TrimStart('/'));
                if (File.Exists(filePath))
                {
                    await ServeStaticFile(context, filePath);
                    return;
                }
            }

            // 检查路由
            if (_routes.TryGetValue(request.Url.AbsolutePath, out var handler))
            {
                await handler(request, response);
            }
            else
            {
                SendErrorResponse(response, HttpStatusCode.NotFound, "Resource not found");
            }
        }
        catch (Exception ex)
        {
            SendErrorResponse(response, HttpStatusCode.InternalServerError, ex.Message);
        }
        finally
        {
            response.Close();
        }
    }

    // 路由处理程序示例
    private async Task HandleRoot(HttpListenerRequest request, HttpListenerResponse response)
    {
        var html = @"



Enhanced Server

    

Enhanced HTTP Server

Test static file

"; await SendResponseAsync(response, "text/html", html); } private async Task HandleEchoApi(HttpListenerRequest request, HttpListenerResponse response) { if (request.HttpMethod == "POST") { using var reader = new StreamReader(request.InputStream, request.ContentEncoding); var body = await reader.ReadToEndAsync(); await SendResponseAsync(response, "application/json", $"{{\"echo\":\"{body}\"}}"); } else { SendErrorResponse(response, HttpStatusCode.MethodNotAllowed, "POST only"); } } private async Task ServeStaticFile(HttpListenerContext context, string filePath) { try { var extension = Path.GetExtension(filePath).ToLower(); var mimeType = extension switch { ".html" => "text/html", ".css" => "text/css", ".js" => "application/javascript", ".jpg" or ".jpeg" => "image/jpeg", ".png" => "image/png", _ => "application/octet-stream" }; var fileBytes = await File.ReadAllBytesAsync(filePath); context.Response.ContentType = mimeType; context.Response.ContentLength64 = fileBytes.Length; await context.Response.OutputStream.WriteAsync(fileBytes, 0, fileBytes.Length); } catch { SendErrorResponse(context.Response, HttpStatusCode.NotFound, "File not found"); } } private async Task SendResponseAsync(HttpListenerResponse response, string contentType, string content) { var buffer = Encoding.UTF8.GetBytes(content); response.ContentType = contentType; response.ContentLength64 = buffer.Length; await response.OutputStream.WriteAsync(buffer, 0, buffer.Length); } private void SendErrorResponse(HttpListenerResponse response, HttpStatusCode statusCode, string message) { var errorResponse = $"{{\"error\":\"{message}\",\"code\":{(int)statusCode}}}"; var buffer = Encoding.UTF8.GetBytes(errorResponse); response.StatusCode = (int)statusCode; response.ContentType = "application/json"; response.ContentLength64 = buffer.Length; response.OutputStream.Write(buffer, 0, buffer.Length); } public void Stop() { _listener.Stop(); _listener.Close(); } } // 使用示例 class Program { static async Task Main(string[] args) { // 创建带静态文件目录的服务器 var server = new EnhancedHttpServer( urlPrefix: "http://localhost:8080/", staticFilesPath: "./wwwroot"); // 添加自定义路由 server.AddRoute("/api/time", async (req, res) => { await server.SendResponseAsync(res, "application/json", $"{{\"time\":\"{DateTime.Now:HH:mm:ss}\"}}"); }); var startTask = server.StartAsync(); Console.WriteLine("Press any key to stop..."); Console.ReadKey(); server.Stop(); await startTask; } }

关键词:C#、.NET、HTTP服务器、HttpListener、异步编程、REST API、静态文件服务、路由系统

简介:本文详细介绍了如何使用C#的HttpListener类实现一个功能完整的HTTP服务器,包含GET/POST请求处理、JSON响应、静态文件服务、路由系统等核心功能,并对比了与ASP.NET Core的差异,适合需要轻量级HTTP服务的开发场景。

《C#实现一个最简单的HTTP服务器.doc》
将本文以doc文档格式下载到电脑,方便收藏和打印
推荐度:
点击下载文档