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

TCP代理/中继网页下载数据损坏、不完整问题的解决求助

解决TCP代理中网络流读取不完整的问题

嘿,我看了你的TCP代理代码,问题出在网络流的读取逻辑上——这也是很多新手写TCP程序时容易踩的坑,直接导致你没完整接收所有数据,才会出现网页为空、图片损坏的情况。我帮你梳理下核心问题,再给出修复后的代码:

核心问题分析

1. 错误依赖DataAvailable判断流结束

DataAvailable只是告诉你当前这一刻流里有没有可读取的数据,不代表对方已经把所有数据发完了。比如网络延迟时,对方还在传输数据,但当前流暂时没数据,DataAvailable就会返回false,你这时候停止读取,自然就丢了后续的数据。

2. 读取时未截取有效数据

每次stream.Read(bytes, 0, bytes.Length)返回的i是实际读到的字节数,但你直接把整个bytes数组加到allBytes里——如果最后一次读取不满buffer,数组里剩下的都是之前的残留数据(比如0字节),这会导致数据冗余甚至损坏。

另外还有个小细节:你用Encoding.Unicode处理HTTP数据是错的,HTTP一般用UTF-8或ASCII,这个会导致日志乱码,但不影响数据传输,不过还是建议修正。


修复后的完整代码

我把关键修改点用注释标出来了,你可以直接替换测试:

using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace TrafficRerouter
{
    class Program
    {
        private static int bufferSize = 8196;
        private static string destIp = "www.projectrho.com";

        static void Main(string[] args)
        {
            StartTcpListener(80);
        }

        private static byte[] SendReceiveRemoteServer(string host, int port, byte[] data)
        {
            try
            {
                // 使用using自动释放资源,避免泄漏
                using var client = new TcpClient(host, port);
                using var stream = client.GetStream();
                
                // 发送请求数据
                stream.Write(data, 0, data.Length);
                var requestStr = Encoding.UTF8.GetString(data);
                Console.Write("\nSent to server: ");
                Col_Out(RemoveBinaryData(requestStr), ConsoleColor.Red);

                var allBytes = new List<byte>();
                var bytes = new byte[bufferSize];
                int i;
                
                // 关键修复1:去掉DataAvailable判断,Read返回0才是流结束的标志
                while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
                {
                    // 关键修复2:只添加实际读取到的i个字节,丢弃buffer里的无效数据
                    allBytes.AddRange(bytes.Take(i));
                }

                var responseStr = Encoding.UTF8.GetString(allBytes.ToArray());
                Console.WriteLine("\nReceived from server: ");
                Col_Out(RemoveBinaryData(responseStr), ConsoleColor.DarkRed);

                return allBytes.ToArray();
            }
            catch (ArgumentNullException e)
            {
                Console.WriteLine("ArgumentNullException: {0}", e);
            }
            catch (SocketException e)
            {
                Console.WriteLine("SocketException: {0}", e);
            }
            Console.WriteLine("\n Press Enter to continue...");
            return new byte[0];
        }

        private static void StartTcpListener(int port)
        {
            TcpListener server = null;
            try
            {
                server = new TcpListener(IPAddress.Loopback, port);
                server.Start();
                while (true)
                {
                    Console.WriteLine("Waiting for a connection... ");
                    using var client = server.AcceptTcpClient();
                    Console.WriteLine("Connected!");
                    using var stream = client.GetStream();

                    var allBytes = new List<byte>();
                    var bytes = new byte[bufferSize];
                    int i;
                    
                    // 同样修复客户端流的读取逻辑
                    while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
                    {
                        allBytes.AddRange(bytes.Take(i));
                    }

                    if (allBytes.Count > 0)
                    {
                        var requestStr = Encoding.UTF8.GetString(allBytes.ToArray());
                        Console.Write("\nReceived from client : ");
                        Col_Out(RemoveBinaryData(requestStr) + '\n', ConsoleColor.DarkGreen);
                        
                        var received = SendReceiveRemoteServer(destIp, 80, allBytes.ToArray());
                        var responseStr = Encoding.UTF8.GetString(received);
                        
                        stream.Write(received, 0, received.Length);
                        Console.Write("\nSent to client : ");
                        Col_Out(RemoveBinaryData(responseStr) + '\n', ConsoleColor.Green);
                    }
                }
            }
            catch (SocketException e)
            {
                Console.WriteLine("SocketException: {0}", e);
            }
            Console.WriteLine("\nHit enter to continue...");
        }

        private static char[] good_chars = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz/.,;:[]=+-_1234567890()*&\n\r".ToArray();
        static string RemoveBinaryData(string s)
        {
            StringBuilder r = new StringBuilder();
            foreach (var c in s)
            {
                if (good_chars.Contains(c))
                    r.Append(c);
            }
            return (r.ToString() + "\n[BINARY_DATA]").Replace("\n", "█ ") + "\n";
        }
        static void Col_Out(string str, ConsoleColor c)
        {
            var oldc = Console.ForegroundColor;
            Console.ForegroundColor = c;
            Console.Write(str);
            Console.ForegroundColor = oldc;
        }
    }
}

修复点详解

  1. 去掉DataAvailable判断:stream.Read()本身会阻塞等待数据,直到对方关闭流(返回0),这才是判断数据传输完成的正确方式,不会因为网络延迟丢数据。
  2. 截取有效字节:用bytes.Take(i)只保留实际读取到的部分,避免把buffer里的残留无效数据混入结果,保证数据完整性。
  3. 用using管理资源:自动释放TcpClient和NetworkStream,不用手动调用Close(),避免资源泄漏。
  4. 编码修正为UTF-8:符合HTTP协议的编码规范,日志输出不会乱码。

这样修改后,你的代理就能完整读取所有网络数据,网页和图片都能正常加载了。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 16:37:36