C#Proxy Server无法正常工作

时间:2013-03-31 21:29:42

标签: c# sockets .net-3.5 proxy

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

  1. 当我逐步调试代码时 - 代理服务器工作正常
  2. 当我在没有调试的情况下启动代理服务器时 - 我在浏览器中出错。
  3. 我真的不知道为什么它像我上面描述的那样有效。也许,某人已经解决了这个问题?

    以下是我的代理服务器的代码:

    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;
        }
    }
    

1 个答案:

答案 0 :(得分:0)

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

然而,在正常执行情况下,情况并非如此。数据将以数据包形式到达,为了知道数据结尾的位置,您必须解析HTTP请求。套接字的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字段并相应地解析。