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)

相关推荐
搬码临时工1 小时前
电脑同时连接内网和外网的方法,附外网连接局域网的操作设置
运维·服务器·网络
程序猿小D3 小时前
第16节 Node.js 文件系统
linux·服务器·前端·node.js·编辑器·vim
midsummer_woo4 小时前
【2025年】解决Burpsuite抓不到https包的问题
网络协议·http·https
IGP94 小时前
20250606-C#知识:委托和事件
开发语言·c#
Kookoos5 小时前
ABP VNext 与 Neo4j:构建基于图数据库的高效关系查询
数据库·c#·.net·neo4j·abp vnext
IT界小黑的对象5 小时前
virtualBox部署ubuntu22.04虚拟机 NAT+host only 宿主机ping不通虚拟机
linux·运维·服务器
我是唐青枫6 小时前
.NET AOT 详解
java·服务器·.net
张鱼小丸子_微辣6 小时前
.Net Framework 4/C# LINQ*
c#
藥瓿亭6 小时前
K8S认证|CKS题库+答案| 4. RBAC - RoleBinding
linux·运维·服务器·云原生·容器·kubernetes·cks
本郡主是喵7 小时前
并发编程 - go版
java·服务器·开发语言