使用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();
    }
}
相关推荐
△曉風殘月〆5 小时前
WPF MVVM入门系列教程(二、依赖属性)
c#·wpf·mvvm
逐·風7 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
m0_6569747410 小时前
C#中的集合类及其使用
开发语言·c#
九鼎科技-Leo10 小时前
了解 .NET 运行时与 .NET 框架:基础概念与相互关系
windows·c#·.net
九鼎科技-Leo12 小时前
什么是 ASP.NET Core?与 ASP.NET MVC 有什么区别?
windows·后端·c#·asp.net·mvc·.net
.net开发12 小时前
WPF怎么通过RestSharp向后端发请求
前端·c#·.net·wpf
小乖兽技术12 小时前
C#与C++交互开发系列(二十):跨进程通信之共享内存(Shared Memory)
c++·c#·交互·ipc
幼儿园园霸柒柒13 小时前
第七章: 7.3求一个3*3的整型矩阵对角线元素之和
c语言·c++·算法·矩阵·c#·1024程序员节
平凡シンプル15 小时前
C# EF 使用
c#
丁德双16 小时前
winform 加载 office excel 插入QRCode图片如何设定位置
c#·excel