You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#中通过Socket完整读取HTTP网络请求?

问题分析与解决

你的代码逻辑是持续调用NetworkStream.Read()直到返回0,但这在HTTP请求场景下行不通——HTTP协议中,客户端发送完请求后通常不会立即关闭TCP连接(尤其是启用Keep-Alive时),所以Read()会一直阻塞,永远等不到返回0的信号,自然无法判断请求结束。

要正确读取HTTP请求,必须遵循HTTP协议规则来判断请求边界,核心思路是:

  • 先读取请求头,直到遇到空行(\r\n\r\n),这是请求头结束的标志
  • 解析请求头中的Content-Length字段,确定请求体的长度(如果有)
  • 根据Content-Length读取对应长度的请求体内容

修改后的代码示例

IPHostEntry host = Dns.GetHostEntry("localhost");
IPAddress ipAddress = host.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, port);

Socket listener = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(localEndPoint);
listener.Listen(1);

Socket networkRequestHandler = listener.Accept();
NetworkStream myNetworkStream = new NetworkStream(networkRequestHandler);

byte[] myReadBuffer = new byte[1024];
StringBuilder headerBuilder = new StringBuilder();
int numberOfBytesRead;

// 读取请求头,直到检测到空行
while (true)
{
    numberOfBytesRead = myNetworkStream.Read(myReadBuffer, 0, myReadBuffer.Length);
    if (numberOfBytesRead == 0) break; // 连接意外中断
    headerBuilder.Append(Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead));
    if (headerBuilder.ToString().Contains("\r\n\r\n"))
        break;
}

string requestHeader = headerBuilder.ToString();
// 解析Content-Length字段
int contentLength = 0;
var contentLengthMatch = System.Text.RegularExpressions.Regex.Match(requestHeader, @"Content-Length:\s*(\d+)");
if (contentLengthMatch.Success)
{
    contentLength = int.Parse(contentLengthMatch.Groups[1].Value);
}

StringBuilder requestBodyBuilder = new StringBuilder();
// 读取指定长度的请求体
if (contentLength > 0)
{
    int bytesReadTotal = 0;
    while (bytesReadTotal < contentLength)
    {
        int bytesToRead = Math.Min(myReadBuffer.Length, contentLength - bytesReadTotal);
        numberOfBytesRead = myNetworkStream.Read(myReadBuffer, 0, bytesToRead);
        if (numberOfBytesRead == 0) break; // 连接意外中断
        requestBodyBuilder.Append(Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead));
        bytesReadTotal += numberOfBytesRead;
    }
}

// 拼接完整请求内容
string fullRequest = requestHeader + requestBodyBuilder.ToString();
Console.WriteLine(fullRequest);

额外说明

  1. 分块编码处理:上述代码仅支持带有Content-Length的请求,如果遇到Transfer-Encoding: chunked的分块请求,需要额外解析分块格式(每个块以十六进制长度+\r\n开头,块内容后接\r\n,最后以0\r\n\r\n结束)。
  2. 编码问题:示例中用ASCII编码,实际HTTP请求可能使用UTF-8等编码,可根据请求头Content-Type中的charset字段调整编码方式。
  3. 生产环境建议:手动基于Socket解析HTTP请求容易遗漏各种边界情况(如压缩、多部分表单、异常请求等),生产环境优先使用成熟的HTTP处理库(如ASP.NET相关组件)。

内容的提问来源于stack exchange,提问作者Mike Croteau

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 11:52:59