本文通过一个仅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[1024];
- 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[1024];
- 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. 空行分隔
4. 响应正文
第五行:发送"商品"给客户
- 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[0];
- string[] parts = requestLine.Split(' ');
- string path = parts.Length > 1 ? parts[1] : "/";
复制代码 这样我们就可以知道用户请求的是 /、/about 还是其他路径。
2. 根据路径返回不同内容
- string html;
- if (path == "/")
- {
- html = "<h1>主页</h1>";
- }
- else if (path == "/about")
- {
- html = "<h1>关于页面</h1>";
- }
- else
- {
- html = "<h1>404 - 页面未找到</h1>";
- }
复制代码 3. 添加文件读取功能
这是从内存响应到文件系统的关键跨越:
[code]static string ReadHtmlFile(string fileName){ try { // 检查文件是否存在 if (!File.Exists(fileName)) { throw new FileNotFoundException(); } // 读取文件内容 string content = File.ReadAllText(fileName, Encoding.UTF8); Console.WriteLine($"
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |