C# HTTP 文件上传、下载服务器

程序需要管理员权限,vs需要管理员打开

首次运行需要执行以下命令注册URL(管理员命令行)

bash 复制代码
netsh advfirewall firewall add rule name="FileShare" dir=in action=allow protocol=TCP localport=8000
ipconfig | findstr "IPv4"
csharp 复制代码
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        string path = @"D:\8000"; // 共享目录
        int port = 8000;
        HttpListener listener = new HttpListener();
        listener.Prefixes.Add($"http://+:{port}/");
        listener.Start();
        Console.WriteLine($"服务器已启动: http://{GetLocalIP()}:{port}");

        while (true)
        {
            var context = listener.GetContext();
            if (context.Request.HttpMethod == "POST")
            {
                ProcessUploadRequest(context, path);
            }
            else
            {
                ProcessRequest(context, path);
            }
        }
    }

    static void ProcessUploadRequest(HttpListenerContext context, string rootPath)
    {
        try
        {
            // 获取上传文件名
            string filename = context.Request.Headers["X-FileName"] ?? Path.GetRandomFileName();
            string filePath = Path.Combine(rootPath, filename);

            using (FileStream fs = new FileStream(filePath, FileMode.Create))
            {
                context.Request.InputStream.CopyTo(fs);
            }

            SendResponse(context, HttpStatusCode.Created, "文件上传成功");
        }
        catch (Exception ex)
        {
            SendResponse(context, HttpStatusCode.InternalServerError, $"上传失败: {ex.Message}");
        }
    }

    static void ProcessRequest(HttpListenerContext context, string rootPath)
    {
        try
        {
            string requestPath = context.Request.Url.LocalPath.TrimStart('/');
            string fullPath = Path.Combine(rootPath, requestPath);

            // 处理文件下载
            if (File.Exists(fullPath))
            {
                using (FileStream fs = File.OpenRead(fullPath))
                {
                    context.Response.ContentType = GetMimeType(Path.GetExtension(fullPath));
                    context.Response.AddHeader("Content-Disposition", $"attachment; filename=\"{Path.GetFileName(fullPath)}\"");
                    fs.CopyTo(context.Response.OutputStream);
                }
            }
            // 处理目录浏览
            else if (Directory.Exists(fullPath))
            {
                string directoryList = GenerateDirectoryListing(fullPath, context.Request.Url.AbsoluteUri);
                byte[] buffer = Encoding.UTF8.GetBytes(directoryList);
                context.Response.ContentType = "text/html; charset=utf-8";
                context.Response.OutputStream.Write(buffer, 0, buffer.Length);
            }
            else
            {
                SendResponse(context, HttpStatusCode.NotFound, "资源不存在");
            }
        }
        catch (Exception ex)
        {
            SendResponse(context, HttpStatusCode.InternalServerError, $"处理请求失败: {ex.Message}");
        }
        finally
        {
            context.Response.Close();
        }
    }

    static string GenerateDirectoryListing(string path, string baseUrl)
    {
        var sb = new StringBuilder();
        sb.Append("<html><head><title>文件列表</title></head><body>");
        sb.Append($"<h1>文件列表 - {path}</h1><ul>");

        // 添加返回上级目录链接
        if (Directory.GetParent(path) != null)
        {
            sb.Append($"<li><a href='{baseUrl}../'>[上级目录]</a></li>");
        }

        // 遍历目录
        foreach (var dir in Directory.GetDirectories(path))
        {
            string dirName = Path.GetFileName(dir);
            sb.Append($"<li><a href='{baseUrl}{dirName}/'>[目录] {dirName}/</a></li>");
        }

        // 遍历文件
        foreach (var file in Directory.GetFiles(path))
        {
            string fileName = Path.GetFileName(file);
            sb.Append($"<li><a href='{baseUrl}{fileName}'>{fileName}</a></li>");
        }

        sb.Append("</ul></body></html>");
        return sb.ToString();
    }

    static void SendResponse(HttpListenerContext context, HttpStatusCode statusCode, string message)
    {
        byte[] buffer = Encoding.UTF8.GetBytes(message);
        context.Response.StatusCode = (int)statusCode;
        context.Response.ContentType = "text/plain; charset=utf-8";
        context.Response.OutputStream.Write(buffer, 0, buffer.Length);
    }

    /***   
    * MIME类型映射类
    * MIME(Multipurpose Internet Mail Extensions)‌ 
    * 类型是一种标准化的方式,用于描述互联网上传输的内容类型(例如文本、图像、视频等)。
    * 它的核心作用是告诉浏览器或客户端‌如何正确处理文件‌(例如直接显示、下载、调用外部程序打开等)
    */
    static string GetMimeType(string extension)
    {
        var mimeTypes = new Dictionary<string, string>
        {
            { ".txt", "text/plain" },
            { ".pdf", "application/pdf" },
            { ".doc", "application/msword" },
            { ".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document" },
            { ".xls", "application/vnd.ms-excel" },
            { ".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" },
            { ".png", "image/png" },
            { ".jpg", "image/jpeg" },
            { ".jpeg", "image/jpeg" },
            { ".gif", "image/gif" },
            { ".zip", "application/zip" }
        };
        return mimeTypes.TryGetValue(extension.ToLower(), out string mime) ? mime : "application/octet-stream";
    }

    static string GetLocalIP()
    {
        return Dns.GetHostEntry(Dns.GetHostName())
            .AddressList.First(ip => ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
            .ToString();
    }
}

文件上传

curl.exe -X POST -H "X-FileName: Git-2.46.2-64-bit.exe" --data-binary "@C:\Users\Ins\Downloads\Git-2.46.2-64-bit.exe" http://192.168.1.242:8000/![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/5cee6643652b4d94ad4c8534673b97b1.png)

相关推荐
mounter62521 分钟前
Linux 7.0 重磅更新:详解 nullfs 如何重塑根文件系统挂载与内核线程隔离
linux·运维·服务器·kernel
左手厨刀右手茼蒿1 小时前
Flutter 组件 http_requests 适配鸿蒙 HarmonyOS 实战:极简网络请求,构建边缘端轻量级 RESTful 通讯架构
网络·flutter·http
-Da-1 小时前
Unix哲学:一切皆文件与网络通信的统一抽象
服务器·unix
A.A呐2 小时前
【Linux第十三章】缓冲区
linux·服务器
想唱rap2 小时前
Linux线程
java·linux·运维·服务器·开发语言·mysql
JFSJFX3 小时前
手机短信误删怎么办?这4种恢复办法亲测有效,轻松找回短信
运维·服务器
CSharp精选营3 小时前
值类型与引用类型:别再只背“栈和堆”了,看这 4 个实际影响
c#·.net·值类型·引用类型·栈和堆·编程指南
AI-Ming4 小时前
程序员转行学习 AI 大模型: 踩坑记录:服务器内存不够,程序被killed
服务器·人工智能·python·gpt·深度学习·学习·agi
路由侠内网穿透4 小时前
本地部署开源工作空间工具 AFFiNE 并实现外部访问
运维·服务器·数据库·物联网·开源
zzzsde4 小时前
【Linux】Ext文件系统(1)
linux·运维·服务器