C# 使用带有袜子代理的 WebClient
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13122369/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Use WebClient with socks proxy
提问by Para
Is there any way to use a socks proxy with WebClient? Specifically with the DownloadStringmethod that it provides?
有什么办法可以使用socks代理WebClient吗?特别DownloadString是它提供的方法?
I don't want to use any third party stuff like privoxy, freecap whatever and I can't use commercial libraries like those from Chilkat. I tried using stuff from http://www.mentalis.org/in fact I used their WebRequestimplementation but they don't seem to have something similar for WebClient.
我不想使用任何第三方的东西,比如 privoxy、freecap,我不能使用像 Chilkat 这样的商业库。我尝试使用来自http://www.mentalis.org/ 的东西,实际上我使用了他们的WebRequest实现,但他们似乎没有类似的东西用于 WebClient。
采纳答案by casperOne
SOCKSis not supported directly by the WebRequest/WebResponseclasses and by extension, the WebClientclass (it relies on WebRequestto do its work).
WebRequest/WebResponse类和扩展名WebClient类(它依赖于WebRequest完成其工作)不直接支持SOCKS。
It really can't, as it works on the transport layer (TCP/IP) and not through a simple redirect to a server that forwards HTTP requests (which is the level that the WebRequest/WebResponseclasses work on).
它真的不能,因为它在传输层 (TCP/IP) 上工作,而不是通过简单的重定向到转发 HTTP 请求的服务器(这是WebRequest/WebResponse类工作的级别)。
You can create a specialized derivation of WebRequest/WebResponse(that uses ProxySocketto handle the low-level handshaking and then) and then create a specialized WebClientclasswhich overrides the GetWebRequestand GetWebResponsemethods.
您可以创建/的专门派生WebRequestWebResponse(ProxySocket用于处理低级握手然后),然后创建一个覆盖和方法的专门WebClient类。GetWebRequestGetWebResponse
Once you have that class substituted for your WebClientinstances, it should work as normal (you might have to set up the proxy in each case where you use it though).
一旦您用该类替换了您的WebClient实例,它应该可以正常工作(尽管您可能必须在使用它的每种情况下设置代理)。
回答by Para
Here is how I ended up doing it, thank you casperOne for the answer
这是我最终的结果,谢谢 casperOne 的回答
public class SocksWebClient : WebClient
{
public IProxyDetails ProxyDetails { get; set; }
public string UserAgent { get; set; }
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest result = null;
if (ProxyDetails != null)
{
if (ProxyDetails.ProxyType == ProxyType.Proxy)
{
result = (HttpWebRequest)WebRequest.Create(address);
result.Proxy = new WebProxy(ProxyDetails.FullProxyAddress);
if (!string.IsNullOrEmpty(UserAgent))
((HttpWebRequest)result).UserAgent = UserAgent;
}
else if (ProxyDetails.ProxyType == ProxyType.Socks)
{
result = SocksHttpWebRequest.Create(address);
result.Proxy = new WebProxy(ProxyDetails.FullProxyAddress);
//TODO: implement user and password
}
else if (ProxyDetails.ProxyType == ProxyType.None)
{
result = (HttpWebRequest)WebRequest.Create(address);
if (!string.IsNullOrEmpty(UserAgent))
((HttpWebRequest)result).UserAgent = UserAgent;
}
}
else
{
result = (HttpWebRequest)WebRequest.Create(address);
if (!string.IsNullOrEmpty(UserAgent))
((HttpWebRequest)result).UserAgent = UserAgent;
}
return result;
}
}
The SocksHttpWebRequestclass is taken from the bloglinked to by @casperOne, the code for which is as follows:
的SocksHttpWebRequest类是从所拍摄的博客由@casperOne,代码为这是如下地连接至:
using System;
using System.Collections.Specialized;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using Org.Mentalis.Network.ProxySocket;
namespace Ditrans
{
public class SocksHttpWebRequest : WebRequest
{
#region Member Variables
private readonly Uri _requestUri;
private WebHeaderCollection _requestHeaders;
private string _method;
private SocksHttpWebResponse _response;
private string _requestMessage;
private byte[] _requestContentBuffer;
// darn MS for making everything internal (yeah, I'm talking about you, System.net.KnownHttpVerb)
static readonly StringCollection validHttpVerbs =
new StringCollection { "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "OPTIONS" };
#endregion
#region Constructor
private SocksHttpWebRequest(Uri requestUri)
{
_requestUri = requestUri;
}
#endregion
#region WebRequest Members
public override WebResponse GetResponse()
{
if (Proxy == null)
{
throw new InvalidOperationException("Proxy property cannot be null.");
}
if (String.IsNullOrEmpty(Method))
{
throw new InvalidOperationException("Method has not been set.");
}
if (RequestSubmitted)
{
return _response;
}
_response = InternalGetResponse();
RequestSubmitted = true;
return _response;
}
public override Uri RequestUri
{
get { return _requestUri; }
}
public override IWebProxy Proxy { get; set; }
public override WebHeaderCollection Headers
{
get
{
if (_requestHeaders == null)
{
_requestHeaders = new WebHeaderCollection();
}
return _requestHeaders;
}
set
{
if (RequestSubmitted)
{
throw new InvalidOperationException("This operation cannot be performed after the request has been submitted.");
}
_requestHeaders = value;
}
}
public bool RequestSubmitted { get; private set; }
public override string Method
{
get
{
return _method ?? "GET";
}
set
{
if (validHttpVerbs.Contains(value))
{
_method = value;
}
else
{
throw new ArgumentOutOfRangeException("value", string.Format("'{0}' is not a known HTTP verb.", value));
}
}
}
public override long ContentLength { get; set; }
public override string ContentType { get; set; }
public override Stream GetRequestStream()
{
if (RequestSubmitted)
{
throw new InvalidOperationException("This operation cannot be performed after the request has been submitted.");
}
if (_requestContentBuffer == null)
{
_requestContentBuffer = new byte[ContentLength];
}
else if (ContentLength == default(long))
{
_requestContentBuffer = new byte[int.MaxValue];
}
else if (_requestContentBuffer.Length != ContentLength)
{
Array.Resize(ref _requestContentBuffer, (int) ContentLength);
}
return new MemoryStream(_requestContentBuffer);
}
#endregion
#region Methods
public static new WebRequest Create(string requestUri)
{
return new SocksHttpWebRequest(new Uri(requestUri));
}
public static new WebRequest Create(Uri requestUri)
{
return new SocksHttpWebRequest(requestUri);
}
private string BuildHttpRequestMessage()
{
if (RequestSubmitted)
{
throw new InvalidOperationException("This operation cannot be performed after the request has been submitted.");
}
var message = new StringBuilder();
message.AppendFormat("{0} {1} HTTP/1.0\r\nHost: {2}\r\n", Method, RequestUri.PathAndQuery, RequestUri.Host);
// add the headers
foreach (var key in Headers.Keys)
{
message.AppendFormat("{0}: {1}\r\n", key, Headers[key.ToString()]);
}
if (!string.IsNullOrEmpty(ContentType))
{
message.AppendFormat("Content-Type: {0}\r\n", ContentType);
}
if (ContentLength > 0)
{
message.AppendFormat("Content-Length: {0}\r\n", ContentLength);
}
// add a blank line to indicate the end of the headers
message.Append("\r\n");
// add content
if(_requestContentBuffer != null && _requestContentBuffer.Length > 0)
{
using (var stream = new MemoryStream(_requestContentBuffer, false))
{
using (var reader = new StreamReader(stream))
{
message.Append(reader.ReadToEnd());
}
}
}
return message.ToString();
}
private SocksHttpWebResponse InternalGetResponse()
{
var response = new StringBuilder();
using (var _socksConnection =
new ProxySocket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
var proxyUri = Proxy.GetProxy(RequestUri);
var ipAddress = GetProxyIpAddress(proxyUri);
_socksConnection.ProxyEndPoint = new IPEndPoint(ipAddress, proxyUri.Port);
_socksConnection.ProxyType = ProxyTypes.Socks5;
// open connection
_socksConnection.Connect(RequestUri.Host, 80);
// send an HTTP request
_socksConnection.Send(Encoding.ASCII.GetBytes(RequestMessage));
// read the HTTP reply
var buffer = new byte[1024];
var bytesReceived = _socksConnection.Receive(buffer);
while (bytesReceived > 0)
{
response.Append(Encoding.ASCII.GetString(buffer, 0, bytesReceived));
bytesReceived = _socksConnection.Receive(buffer);
}
}
return new SocksHttpWebResponse(response.ToString());
}
private static IPAddress GetProxyIpAddress(Uri proxyUri)
{
IPAddress ipAddress;
if (!IPAddress.TryParse(proxyUri.Host, out ipAddress))
{
try
{
return Dns.GetHostEntry(proxyUri.Host).AddressList[0];
}
catch (Exception e)
{
throw new InvalidOperationException(
string.Format("Unable to resolve proxy hostname '{0}' to a valid IP address.", proxyUri.Host), e);
}
}
return ipAddress;
}
#endregion
#region Properties
public string RequestMessage
{
get
{
if (string.IsNullOrEmpty(_requestMessage))
{
_requestMessage = BuildHttpRequestMessage();
}
return _requestMessage;
}
}
#endregion
}
}
Note that, as @casperOne pointed out, this makes use of a (free) third party library called ProxySocket.
请注意,正如@casperOne 指出的那样,这使用了一个名为ProxySocket的(免费)第三方库。
回答by Martin
I came across this aswell and found the nice BetterHttpClient
我也遇到了这个并找到了不错的BetterHttpClient
It derives from WebClient and allows you to specify a socks proxy:
它派生自 WebClient 并允许您指定袜子代理:
BetterHttpClient.HttpClient client = new BetterHttpClient.HttpClient(new BetterHttpClient.Proxy("IP address", port, BetterHttpClient.ProxyTypeEnum.Socks));
回答by Mohammad
I was looking for library in order to do this. finally i found the MihaZupan/HttpToSocks5Proxyit's a real lifesaver. just like this you can use it:
我正在寻找图书馆来做到这一点。最后我发现MihaZupan/HttpToSocks5Proxy它是一个真正的救星。就像这样你可以使用它:
using MihaZupan;
var proxy = new HttpToSocks5Proxy("127.0.0.1", 1080,
"username", "password" // optional
);
var handler = new HttpClientHandler { Proxy = proxy };
HttpClient httpClient = new HttpClient(handler, true);
var result = await httpClient.SendAsync(
new HttpRequestMessage(HttpMethod.Get, "https://httpbin.org/ip"));
Console.WriteLine("HTTPS GET: " + await result.Content.ReadAsStringAsync());
If you want a more convenient, WebClient-esque API for reading the content, you can wrap the response-read calls into an extension method:
如果您想要更方便的WebClient-esque API 来读取内容,可以将响应读取调用包装到扩展方法中:
public static class ExtensionMethods
{
public static async Task<string> DownloadStringAsync(this HttpClient client, string url)
{
var response = await client.SendAsync(new HttpRequestMessage(
HttpMethod.Get, url));
return await response.Content.ReadAsStringAsync();
}
}

