使用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();
}
}