凤清昶 发表于 2025-12-3 17:00:34

从20行代码理解HTTP服务器:用原始Socket揭开Web协议的神秘面纱

本文通过一个仅20行的C#代码示例,深入讲解HTTP服务器如何工作,帮助你理解浏览器和服务器之间的通信本质。
引言:HTTP的真相

当我们每天使用浏览器访问网站时,是否曾思考过背后发生了什么?浏览器和服务器之间到底在交流什么?今天,我将用最精简的代码(仅20行!)展示HTTP服务器的核心原理,并逐步扩展为一个功能完整的服务器。
核心代码:20行的HTTP服务器

using System.Net;
using System.Net.Sockets;
using System.Text;

class CoreHttpServer
{
    static void Main()
    {
      // 1. 创建TCP监听器
      TcpListener server = new TcpListener(IPAddress.Any, 9011);
      server.Start();
      Console.WriteLine("服务器启动...");

      while (true)
      {
            // 2. 接受连接
            TcpClient client = server.AcceptTcpClient();
            
            // 3. 读取请求
            NetworkStream stream = client.GetStream();
            byte[] buffer = new byte;
            int bytes = stream.Read(buffer, 0, buffer.Length);
            
            // 4. 构建响应
            string html = "<h1>Hello Socket!</h1><p>原始HTTP</p>";
            string response =
                "HTTP/1.1 200 OK\r\n" +
                "Content-Type: text/html\r\n" +
                $"Content-Length: {Encoding.UTF8.GetByteCount(html)}\r\n" +
                "\r\n" + html;
            
            // 5. 发送响应
            byte[] data = Encoding.UTF8.GetBytes(response);
            stream.Write(data, 0, data.Length);
            
            client.Close();
      }
    }
}这20行代码包含了HTTP服务器的一切本质!让我们逐行解析:
第一行:建立TCP连接通道

TcpListener server = new TcpListener(IPAddress.Any, 9011);这行代码创建了一个TCP监听器,就像是开了一家商店,门牌号是9011:

[*]IPAddress.Any:监听所有网络接口
[*]9011:端口号,服务器的"门牌号"
关键理解:HTTP建立在TCP之上。TCP是"可靠传输管道",HTTP是"管道中传输的文本协议"。
第二行:等待客户上门

TcpClient client = server.AcceptTcpClient();当浏览器访问 http://localhost:9011 时:

[*]浏览器建立TCP连接到端口9011
[*]AcceptTcpClient() 接受这个连接
[*]返回一个 TcpClient 对象,代表这个连接通道
第三行:接收浏览器的"订单"

NetworkStream stream = client.GetStream();
byte[] buffer = new byte;
int bytes = stream.Read(buffer, 0, buffer.Length);这里发生了以下事情:
浏览器发送的原始文本:
GET / HTTP/1.1\r\n
Host: localhost:9011\r\n
User-Agent: Mozilla/5.0\r\n
Accept: text/html\r\n
\r\n注意最后的 \r\n\r\n(空行),这是HTTP协议规定的:头部结束的标记。
第四行:准备"商品"(构建响应)

string html = "<h1>Hello Socket!</h1><p>原始HTTP</p>";
string response =
    "HTTP/1.1 200 OK\r\n" +
    "Content-Type: text/html\r\n" +
    $"Content-Length: {Encoding.UTF8.GetByteCount(html)}\r\n" +
    "\r\n" + html;HTTP响应由三部分组成:
1. 状态行:HTTP/1.1 200 OK


[*]HTTP/1.1:协议版本
[*]200:状态码(成功)
[*]OK:状态描述
2. 响应头部


[*]Content-Type: text/html:告诉浏览器这是HTML
[*]Content-Length: ...:告诉浏览器内容有多长(至关重要!)
3. 空行分隔


[*]\r\n:必须的空行,分隔头部和正文
4. 响应正文


[*]HTML内容
第五行:发送"商品"给客户

byte[] data = Encoding.UTF8.GetBytes(response);
stream.Write(data, 0, data.Length);
client.Close();文本 → 字节 → 通过网络发送 → 关闭连接。完整的一次HTTP交互完成!
从20行到完整服务器

现在,让我们基于这20行核心代码,构建一个功能更完整的服务器:
1. 添加请求解析

// 解析浏览器请求的路径
string requestText = Encoding.UTF8.GetString(buffer, 0, bytes);
string[] lines = requestText.Split("\r\n");
string requestLine = lines;
string[] parts = requestLine.Split(' ');
string path = parts.Length > 1 ? parts : "/";这样我们就可以知道用户请求的是 /、/about 还是其他路径。
2. 根据路径返回不同内容

string html;
if (path == "/")
{
    html = "<h1>主页</h1>";
}
else if (path == "/about")
{
    html = "<h1>关于页面</h1>";
}
else
{
    html = "<h1>404 - 页面未找到</h1>";
}3. 添加文件读取功能

这是从内存响应到文件系统的关键跨越:
static string ReadHtmlFile(string fileName){    try    {      // 检查文件是否存在      if (!File.Exists(fileName))      {            throw new FileNotFoundException();      }                // 读取文件内容      string content = File.ReadAllText(fileName, Encoding.UTF8);      Console.WriteLine($"
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

何书艺 发表于 前天 19:02

感谢分享,下载保存了,貌似很强大

荏牌 发表于 15 小时前

懂技术并乐意极积无私分享的人越来越少。珍惜
页: [1]
查看完整版本: 从20行代码理解HTTP服务器:用原始Socket揭开Web协议的神秘面纱