使用套接字的简单Http代理:问题

我正在尝试学习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)学习sockets的其他建议是什么?

谢谢你的时间。 最好的祝福。

1)如果在您调用它的瞬间缓冲区中没有可用数据,则Socket.Available返回零。 如果没有可用的数据,Socket.Read将阻止(等待)数据到达。 这就是区别。 通过调用Read,您可以等待数据。 通过检查可用,您不要等待。 因此,如果您在数据到达之前碰巧看到可用,它将为零。

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

3)这两个电话是相同的。

至于4)和5),CLR套接字API非常接近原始的C API,所以如果很难找到C#教程,你可以查看C语言中有关良好套接字编程的任何教程或信息,以获得更多提示。

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

最后,当您最后一次调用Send将所有数据发送回客户端时,它可能不会一次性发送所有数据。 因此,您应该循环并继续发送剩余的内容,直到它们全部发送完毕为止。

如果这是您的第一个Sockets投资,我强烈建议您从“聊天”应用程序开始。 无论哪种方式,一个有价值的测试工具也是一个名为WinsockTool的小工具。

不知道您是否可以在此处直接将链接发布到.MSI文件,但如果这不起作用:

http://www.isatools.org/tools/winsocktool.msi

Google for site:isatools.org WinsockTool

这对于连接到“服务器”套接字并发送原始文本和查看原始响应而不必创建客户端应用程序非常棒。