.NET中的HTTP代理支持实际上不支持TcpClient或Socket等较低级别的类。但我想通过支持'CONNECT'命令的HTTP代理连接TCPServer(ip,port)。
所以我需要执行以下步骤:
CONNECT Host:Port HTTP/1.1<CR><LF>
<CR><LF>
HTTP/1.X 200
,则连接成功。其实我这样做没有代理
TcpClient _client;
NetworkStream _stream;
public static async Task<bool> ConnectAsync(string hostname, int port)
{
_client = new TcpClient();
await _client.ConnectAsync(hostname, port).ConfigureAwait(false);
_stream = conn._client.GetStream();
..... Do some stuff
// Connexion OK
return true;
}
如何在连接TcpClient之前使用代理和凭据?
答案 0 :(得分:4)
我找到了基于.NET: Connecting a TcpClient through an HTTP proxy with authentication和Bypass the proxy using TcpClient
的解决方案TcpClient _client;
NetworkStream _stream;
public TcpClient ProxyTcpClient(string targetHost, int targetPort, string httpProxyHost, int httpProxyPort, string proxyUserName, string proxyPassword)
{
const BindingFlags Flags = BindingFlags.NonPublic | BindingFlags.Instance;
Uri proxyUri = new UriBuilder
{
Scheme = Uri.UriSchemeHttp,
Host = httpProxyHost,
Port = httpProxyPort
}.Uri;
Uri targetUri = new UriBuilder
{
Scheme = Uri.UriSchemeHttp,
Host = targetHost,
Port = targetPort
}.Uri;
WebProxy webProxy = new WebProxy(proxyUri, true);
webProxy.Credentials = new NetworkCredential(proxyUserName, proxyPassword);
WebRequest request = WebRequest.Create(targetUri);
request.Proxy = webProxy;
request.Method = "CONNECT";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
Type responseType = responseStream.GetType();
PropertyInfo connectionProperty = responseType.GetProperty("Connection", Flags);
var connection = connectionProperty.GetValue(responseStream, null);
Type connectionType = connection.GetType();
PropertyInfo networkStreamProperty = connectionType.GetProperty("NetworkStream", Flags);
NetworkStream networkStream = (NetworkStream)networkStreamProperty.GetValue(connection, null);
Type nsType = networkStream.GetType();
PropertyInfo socketProperty = nsType.GetProperty("Socket", Flags);
Socket socket = (Socket)socketProperty.GetValue(networkStream, null);
return new TcpClient { Client = socket };
}
public static async Task<bool> ConnectAsync(string hostname, int port)
{
_client = ProxyTcpClient("IPTargetHost", 1234, "IPProxyHost", 5678, "Userproxy", "Userppwd");
_stream = conn._client.GetStream();
..... Do some stuff
// Connexion OK
return true;
}
答案 1 :(得分:2)
如果代理需要基本身份验证,要扩展 Rychu's 答案,请将标头添加到连接消息中
var auth = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{proxy.Login}:{proxy.Password}"));
var connectMessage = Encoding.UTF8.GetBytes($"CONNECT {host}:{port} HTTP/1.1\nProxy-Authorization: Basic {auth}\n\n");
socket.Send(connectMessage);
答案 2 :(得分:1)
我们设法使用.Net的Socket
来实现它。 Nuget程序包称为Filemail.ProxiedTcpClient。代码很简单:
public static TcpClient CreateProxied(Uri proxy, Uri destination)
{
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(proxy.Host, proxy.Port);
var connectMessage = Encoding.UTF8.GetBytes($"CONNECT {destination.Host}:{destination.Port} HTTP/1.1{Environment.NewLine}{Environment.NewLine}");
socket.Send(connectMessage);
byte[] receiveBuffer = new byte[1024];
var received = socket.Receive(receiveBuffer);
var response = ASCIIEncoding.ASCII.GetString(receiveBuffer, 0, received);
if (!response.Contains("200 OK"))
{
throw new Exception($"Error connecting to proxy server {destination.Host}:{destination.Port}. Response: {response}");
}
return new TcpClient
{
Client = socket
};
}