c# - 使用套接字的简单 Http 代理 : Questions

标签 c# .net sockets proxy

<分区>

我正在尝试了解套接字在 C# 中的工作原理。我的想法是编写一个简单的 http 代理: 这是我的代码:

using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;

class Program
{
    static void Main(string[] args)
    {
        ThreadPool.SetMaxThreads(1000, 500);
        ThreadPool.SetMinThreads(500, 250);

        TcpListener listener = new TcpListener(IPAddress.Any, 8282);
        listener.Start();

        while (true)
        {
            Socket client = listener.AcceptSocket();
            ThreadPool.QueueUserWorkItem(ProcessSocket, client);
        }
    }

    private static readonly string patternHostPort = @"(Host:\s)(\S+)(:)(\d+)";
    private static readonly string patternHost = @"(Host:\s)(\S+)";
    private static Regex regexHostPort = new Regex(patternHostPort);
    private static Regex regexHost = new Regex(patternHost);

    static void ProcessSocket(object request)
    {
        string requestString = string.Empty;
        MemoryStream mStream = new MemoryStream();
        int bytesReceived;
        int bytesSended;
        byte[] buffer;
        byte[] byteOriginalRequest;

        Socket socketClient = (Socket)request;
        Console.WriteLine("Incoming connection: " + socketClient.RemoteEndPoint.ToString());

        buffer = new byte[4096];

        bytesReceived = socketClient.Receive(buffer, 0, buffer.Length, SocketFlags.None);
        mStream.Write(buffer, 0, bytesReceived);
        while (socketClient.Available > 0)
        {
            bytesReceived = socketClient.Receive(buffer, 0, buffer.Length, SocketFlags.None);
            mStream.Write(buffer, 0, bytesReceived);
        }

        mStream.Close();

        byteOriginalRequest = mStream.ToArray();
        requestString = Encoding.ASCII.GetString(byteOriginalRequest);
        //Console.WriteLine(requestString);

        #region Get requested Host and Port
        string srvHost = string.Empty;
        string srvPort = string.Empty;

        Match matchHostPort = regexHostPort.Match(requestString);
        if (matchHostPort.Success)
        {
            srvHost = matchHostPort.Groups[2].Value;
            srvPort = matchHostPort.Groups[4].Value;
        }
        else
        {
            Match matchHost = regexHost.Match(requestString);
            if (matchHost.Success)
            {
                srvHost = matchHost.Groups[2].Value;
                srvPort = "80";
            }
            else
            {
                Console.WriteLine("Invalid request?");
            }
        }
        #endregion

        Console.WriteLine(string.Format("Request to {0} on port {1}", srvHost, srvPort));

        IPAddress[] ipAddress = Dns.GetHostAddresses(srvHost);
        IPEndPoint endPoint = new IPEndPoint(ipAddress[0], int.Parse(srvPort));

        using (Socket socketProxy = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp))
        {
            socketProxy.Connect(endPoint);

            bytesSended = socketProxy.Send(byteOriginalRequest, byteOriginalRequest.Length, SocketFlags.None);

            MemoryStream m2Stream = new MemoryStream();
            bytesReceived = 1;
            while (bytesReceived > 0)
            {
                bytesReceived = socketProxy.Receive(buffer, 0, buffer.Length, SocketFlags.None);
                m2Stream.Write(buffer, 0, bytesReceived);
            }

            m2Stream.Close();
            byte[] finalResponse = m2Stream.ToArray();
            string stringFinalResponse = Encoding.ASCII.GetString(finalResponse);

            bytesSended = socketClient.Send(finalResponse, finalResponse.Length, SocketFlags.None);

            socketProxy.Close();
        }

        socketClient.Close();
    }
}

这里有一些问题:

1) 为什么我要替换这个

bytesReceived = 1;
while (bytesReceived > 0)
{
    bytesReceived = socketProxy.Receive(buffer, 0, buffer.Length, SocketFlags.None);
    m2Stream.Write(buffer, 0, bytesReceived);
}

有了这个

while (socketProxy.Available > 0)
{
    bytesReceived = socketProxy.Receive(buffer, 0, buffer.Length, SocketFlags.None);
    m2Stream.Write(buffer, 0, bytesReceived);
}

我只得到一个空白页面(在浏览器中)?

2) 可能与 1) 有关,但是......使用当前代码加载任何简单页面(如谷歌)需要一段时间,调试我发现问题可能是在 socketProxy.Receive ... 但我不知道为什么。

3)有什么区别

socketProxy.Send(byteOriginalRequest, byteOriginalRequest.Length, SocketFlags.None);

socketProxy.Send(byteOriginalRequest);

? (更多参数不是有效答案:)

4) 有推荐读物吗?书籍、教程、...?

5) 还有其他学习套接字的建议吗?

感谢您的宝贵时间。 最好的问候。

最佳答案

1) 如果在您调用它时缓冲区中没有可用数据,Socket.Available 将返回零。如果尚无可用数据,Socket.Read 将阻塞(等待)数据到达。这就是区别。通过调用 Read,您可以让它等待数据。通过检查 Available,您不会让它等待。因此,如果您恰好在数据到达之前查看 Available,它将为零。

2) 不确定为什么它很慢,但是您不需要为发送回客户端的数据使用内存缓冲区,因为您不检查它。只需从一个套接字读取并直接写入另一个套接字。

3) 两个调用是相同的。

至于 4) 和 5),CLR 套接字 API 非常接近原始的 C API,因此如果很难找到 C# 教程,您可以查看任何教程或有关使用 C 进行良好套接字编程的信息以获得更多提示.

此外,您应该在调用 Close 之前调用 Shutdown。当您调用 Close 时,套接字断开连接,这意味着另一端失去连接并且无法读取任何他们尚未读取的数据 - 另一端的缓冲区被操作系统破坏并且数据被丢弃。调用 Shutdown(SocketShutdown.Send) 会导致另一端在调用 Read 时(在读取剩余数据之后)获得零字节。然后你调用 Read 直到它返回零,这告诉你另一端已经获得了所有数据并且也调用了 Shutdown。然后你可以调用关闭。

最后,当您最后一次调用 Send 将所有数据发送回客户端时,它可能不会一次性发送所有数据。所以你应该循环并继续发送剩下的任何东西,直到它全部发送完。

关于c# - 使用套接字的简单 Http 代理 : Questions,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/534512/

相关文章:

java - 如何创建套接字以接收文本和图像

c# - ASP.NET 编译错误(无法调用代码隐藏文件中的方法)

c# - 将 XML 转换为数据表

.net - SonarQube 后处理失败,原因未知

c# - 申请路径

C#检测哪个显卡驱动视频

c# - 如何在每天的给定时间执行代码?

c# - 如何验证 JObject 是否属于特定类型

Android Http 服务器和破损的管道

java - 我如何识别 Java 套接字中的 EOF?