【问题标题】:C# Proxy Server doesn't work correctlyC# 代理服务器无法正常工作
【发布时间】:2013-03-22 00:19:32
【问题描述】:

我正在使用套接字在 .NET 中开发代理服务器,我发现对代码执行非常感兴趣:

  1. 当我逐步调试代码时 - 代理服务器工作正常
  2. 当我在没有调试的情况下启动代理服务器时 - 我在浏览器中出现错误。

我真的不知道为什么它会像我上面描述的那样工作。也许,有人已经解决了这个问题?

这是我的代理服务器的代码:

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

namespace Statistiks.Lib
{
    internal class NetworkMonitor
    {
        private readonly IList<string> _denied;
        private readonly Socket _srvSocket;
        private readonly Thread _srvThread;

        public NetworkMonitor(int port, IList<string> deniedList)
        {
            _denied = deniedList;
            _srvSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
                                    ProtocolType.Tcp);
            _srvSocket.Bind(new IPEndPoint(IPAddress.Loopback, port));
            _srvThread = new Thread(ProxyServerThread);
            _srvThread.Start(_srvSocket);
        }

        private void ProxyServerThread(object obj)
        {
            var srv = obj as Socket;
            srv.Listen(1024);
            while (true)
            {
                Socket clientSocket = srv.Accept();
                ThreadPool.QueueUserWorkItem(cSocket =>
                    {
                        var client = cSocket as Socket;
                        if (client.Available <= 0)
                        {
                            client.Shutdown(SocketShutdown.Both);
                            client.Close();
                            return;
                        }
                        var recieveBuf = new byte[client.Available];
                        client.Receive(recieveBuf, SocketFlags.None);
                        var ni = new NetworkInfo();
                        try
                        {
                            ni.Url = new Uri(Encoding.ASCII.GetString(recieveBuf)
                                                     .Split(new[] {"\r\n"}, StringSplitOptions.RemoveEmptyEntries)[0]
                                                 .Split(' ')[1]);
                        }
                        catch (ArgumentOutOfRangeException)
                        {
                            client.Shutdown(SocketShutdown.Both);
                            client.Close();
                            return;
                        }
                        var forwardedSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
                                                         ProtocolType.Tcp);
                        forwardedSocket.Connect(Dns.GetHostAddresses(ni.Url.Host)[0], ni.Url.Port);
                        forwardedSocket.Send(recieveBuf, SocketFlags.None);
                        recieveBuf = new byte[forwardedSocket.Available];
                        forwardedSocket.Receive(recieveBuf, SocketFlags.None);
                        client.Send(recieveBuf, SocketFlags.None);
                        forwardedSocket.Shutdown(SocketShutdown.Both);
                        forwardedSocket.Disconnect(false);
                        client.Shutdown(SocketShutdown.Both);
                        client.Disconnect(false);
                        forwardedSocket.Close();
                        client.Close();
                    }, clientSocket);
            }
        }
    }

    internal struct NetworkInfo
    {
        internal Uri Url;
    }
}

【问题讨论】:

  • 听起来像是时间问题。您很可能在收到任何数据之前检查可用数据,从而导致连接关闭。此外,使用 while 循环来接收数据(其中一些可能已准备好读取,但可能还不是全部)。

标签: c# sockets .net-3.5 proxy


【解决方案1】:

调试器下的不同结果可能是因为您的所有数据都适合套接字缓冲区,并且调试的额外延迟允许所有数据在调用Receive之前到达。

然而,在正常执行下,情况并非如此。数据将以数据包的形式到达,为了知道数据的结尾在哪里,您必须解析您的 HTTP 请求。 Socket 的Available 属性只表示此时缓冲区中有多少数据,而不是整个消息的长度。虽然使用原始套接字绝对可以读取,但使用NetworkStream 更容易:

IEnumerable<string> ReadRequestHeaders(Socket s)
{
    using (var stream = new NetworkStream(s, false))
    using (var reader = new StreamReader(stream))
    {
        while (true)
        {
            var line = reader.ReadLine();
            if (line == "")
                break;

            yield return line;
        }
    }
}

HTTP 消息的其余部分也是如此 - 为了正确转发它,您必须知道它的结束位置,这意味着了解 Content-Length 或 Transfer-Encoding 字段并进行相应的解析。

【讨论】:

    猜你喜欢
    • 2014-12-28
    • 2012-01-20
    • 1970-01-01
    • 2015-03-06
    • 1970-01-01
    • 2017-06-02
    • 2015-10-27
    • 2016-12-30
    • 1970-01-01
    相关资源
    最近更新 更多