使用C#的Socket从头实现的带有文件上传和下载功能的HTTP服务器

使用C#和Socket从头实现的带有文件上传和下载功能的HTTP服务器。它支持GET、POST请求方法,并能处理URL参数、请求体以及文件上传和下载。

cs 复制代码
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;

class HttpServer
{
    public static void Main(string[] args)
    {
        const int port = 8080;
        TcpListener listener = new TcpListener(IPAddress.Any, port);
        listener.Start();
        Console.WriteLine("HTTP server is running on port {0}...", port);

        while (true)
        {
            TcpClient client = listener.AcceptTcpClient();
            ProcessClientRequest(client);
        }
    }

    public static void ProcessClientRequest(TcpClient client)
    {
        using (NetworkStream stream = client.GetStream())
        {
            // 读取请求数据
            byte[] buffer = new byte[4096];
            int bytesRead = stream.Read(buffer, 0, buffer.Length);
            string requestString = Encoding.UTF8.GetString(buffer, 0, bytesRead);

            // 解析请求
            HttpRequest request = ParseRequest(requestString);

            // 构造响应数据
            HttpResponse response = BuildResponse(request);

            // 发送响应头
            byte[] responseHeaderBytes = Encoding.UTF8.GetBytes(response.GetHeaderString());
            stream.Write(responseHeaderBytes, 0, responseHeaderBytes.Length);

            // 发送响应体(如果有)
            if (response.ContentStream != null)
            {
                byte[] bufferBytes = new byte[4096];
                int bytesToRead;
                while ((bytesToRead = response.ContentStream.Read(bufferBytes, 0, bufferBytes.Length)) > 0)
                {
                    stream.Write(bufferBytes, 0, bytesToRead);
                }
                response.ContentStream.Close();
            }
        }

        client.Close();
    }

    public static HttpRequest ParseRequest(string requestString)
    {
        var request = new HttpRequest();

        string[] lines = requestString.Split(new[] { "\r\n" }, StringSplitOptions.None);

        // 解析请求行
        string[] requestLineParts = lines[0].Split(' ');
        request.Method = requestLineParts[0].ToUpper();
        request.Path = requestLineParts[1];

        // 解析请求头
        for (int i = 1; i < lines.Length; i++)
        {
            string[] headerParts = lines[i].Split(':');
            if (headerParts.Length == 2)
            {
                string key = headerParts[0].Trim();
                string value = headerParts[1].Trim();
                request.Headers[key] = value;
            }
        }

        // 解析请求体(仅对POST请求处理)
        if (request.Method == "POST")
        {
            int bodyIndex = Array.IndexOf(lines, "");
            if (bodyIndex != -1 && bodyIndex < lines.Length - 1)
            {
                request.Body = lines[bodyIndex + 1];
            }
        }

        return request;
    }

    public static HttpResponse BuildResponse(HttpRequest request)
    {
        var response = new HttpResponse();

        // 设置响应头信息
        response.StatusCode = 200;
        response.StatusDescription = "OK";
        response.Headers["Content-Type"] = "text/plain; charset=utf-8";

        // 处理文件上传
        if (request.Method == "POST" && request.Headers.ContainsKey("Content-Disposition"))
        {
            string filename = GetFilenameFromContentDisposition(request.Headers["Content-Disposition"]);
            using (FileStream fileStream = File.Create(filename))
            {
                using (StreamWriter writer = new StreamWriter(fileStream))
                {
                    writer.Write(request.Body);
                }
            }

            response.SetContent("File uploaded successfully.");
        }
        // 处理文件下载
        else if (request.Method == "GET" && request.Path.StartsWith("/download/"))
        {
            string filepath = request.Path.Substring("/download/".Length);
            if (File.Exists(filepath))
            {
                response.StatusCode = 200;
                response.StatusDescription = "OK";
                response.Headers["Content-Type"] = "application/octet-stream";
                response.Headers["Content-Disposition"] = $"attachment; filename=\"{Path.GetFileName(filepath)}\"";
                response.ContentStream = File.OpenRead(filepath);
            }
            else
            {
                response.StatusCode = 404;
                response.StatusDescription = "Not Found";
                response.SetContent("File not found.");
            }
        }
        // 默认返回文本内容
        else
        {
            string content = "Welcome to the HTTP server.";
            response.SetContent(content);
        }

        return response;
    }

    public static string GetFilenameFromContentDisposition(string contentDisposition)
    {
        const string keyword = "filename=\"";
        int startIndex = contentDisposition.IndexOf(keyword) + keyword.Length;
        int endIndex = contentDisposition.IndexOf("\"", startIndex);
        return contentDisposition.Substring(startIndex, endIndex - startIndex);
    }
}

class HttpRequest
{
    public string Method { get; set; }
    public string Path { get; set; }
    public IDictionary<string, string> Headers { get; set; } = new Dictionary<string, string>();
    public string Body { get; set; }
}

class HttpResponse
{
    public int StatusCode { get; set; }
    public string StatusDescription { get; set; }
    public IDictionary<string, string> Headers { get; set; } = new Dictionary<string, string>();
    public Stream ContentStream { get; set; }

    public void SetContent(string content)
    {
        byte[] contentBytes = Encoding.UTF8.GetBytes(content);
        ContentStream = new MemoryStream(contentBytes);
        Headers["Content-Length"] = contentBytes.Length.ToString();
    }

    public string GetHeaderString()
    {
        StringBuilder builder = new StringBuilder();
        builder.AppendFormat("HTTP/1.1 {0} {1}\r\n", StatusCode, StatusDescription);
        foreach (var header in Headers)
        {
            builder.AppendFormat("{0}: {1}\r\n", header.Key, header.Value);
        }
        builder.Append("\r\n");
        return builder.ToString();
    }
}
相关推荐
向宇it9 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
九鼎科技-Leo10 小时前
什么是 WPF 中的依赖属性?有什么作用?
windows·c#·.net·wpf
Heaphaestus,RC11 小时前
【Unity3D】获取 GameObject 的完整层级结构
unity·c#
baivfhpwxf202311 小时前
C# 5000 转16进制 字节(激光器串口通讯生成指定格式命令)
开发语言·c#
直裾11 小时前
Scala全文单词统计
开发语言·c#·scala
ZwaterZ13 小时前
vue el-table表格点击某行触发事件&&操作栏点击和row-click冲突问题
前端·vue.js·elementui·c#·vue
ZwaterZ15 小时前
el-table-column自动生成序号&&在序号前插入图标
前端·javascript·c#·vue
SRC_BLUE_1718 小时前
SQLI LABS | Less-55 GET-Challenge-Union-14 Queries Allowed-Variation 2
oracle·c#·less
yngsqq18 小时前
037集——JoinEntities连接多段线polyline和圆弧arc(CAD—C#二次开发入门)
开发语言·c#·swift
Zԅ(¯ㅂ¯ԅ)18 小时前
C#桌面应用制作计算器进阶版01
开发语言·c#