Выберите одно из многих подключений к Интернету для приложения
У меня есть компьютер с несколькими различными подключениями к Интернету. LAN, WLAN, WiFi или 3G. Все они активны, и машина может использовать любой из них.
Теперь я хочу сказать своему приложению использовать одно из доступных подключений. Например, я хочу указать моему приложению использовать только WiFi, в то время как другое программное обеспечение может использовать что-то другое.
В моем приложении C# я использую такие классы, как HttpWebRequest
а также HttpWebResponse
,
Это вообще возможно?
4 ответа
Это несколько продвинутая функциональность, которая абстрагируется как HttpWebRequest, WebRequest, WebClient и так далее. Вы можете, однако, сделать это с помощью TcpClient
(используя конструктор, принимающий локальную конечную точку) или используя сокеты и вызывая Socket.Bind.
Используйте метод Bind, если вам нужно использовать конкретную локальную конечную точку. Вы должны вызвать Bind, прежде чем сможете вызвать метод Listen. Вам не нужно вызывать Bind перед использованием метода Connect, если вам не нужно использовать конкретную локальную конечную точку.
Привязать к локальной конечной точке для интерфейса, который вы хотите использовать. Если ваш локальный компьютер имеет IP-адрес 192.168.0.10 для адреса WiFi, то использование этой локальной конечной точки заставит сокеты использовать этот интерфейс. Значение по умолчанию не ограничено (на самом деле 0.0.0.0), что говорит сетевому стеку автоматически разрешать интерфейс, который вы хотите обойти.
Вот пример кода, основанный на комментарии Эндрю. Обратите внимание, что указание 0 в качестве порта локальной конечной точки означает, что он динамический.
using System.Net;
using System.Net.Sockets;
public static class ConsoleApp
{
public static void Main()
{
{
// 192.168.20.54 is my local network with internet accessibility
var localEndPoint = new IPEndPoint(IPAddress.Parse("192.168.20.54"), port: 0);
var tcpClient = new TcpClient(localEndPoint);
// No exception thrown.
tcpClient.Connect("stackru.com", 80);
}
{
// 192.168.2.49 is my vpn, having no default gateway and unable to forward
// packages to anything that is outside of 192.168.2.x
var localEndPoint = new IPEndPoint(IPAddress.Parse("192.168.2.49"), port: 0);
var tcpClient = new TcpClient(localEndPoint);
// SocketException: A socket operation was attempted to an unreachable network 64.34.119.12:80
tcpClient.Connect("stackru.com", 80);
}
}
}
См. Эту запись блога MSDN на ServicePoint.BindIPEndPointDelegate. В нем объясняется, как явно создать локальную конечную точку, которая будет использоваться HttpWebRequest.
Например, чтобы связать с 192.168.16.100:
WebRequest webReq = WebRequest.Create(myUri);
HttpWebRequest httpRequest = (HttpWebRequest)webReq;
httpRequest.ServicePoint.BindIPEndPointDelegate =
new BindIPEndPoint(BindIPEndPointCallback);
...
private static IPEndPoint BindIPEndPointCallback(ServicePoint servicePoint,
IPEndPoint remoteEndPoint,
int retryCount)
{
if (remoteEndPoint.AddressFamily == AddressFamily.InterNetwork)
{
return new IPEndPoint(IPAddress.Parse("192.168.16.100"), 0);
}
// Just use the default endpoint.
return null;
}
Вы определенно можете сделать это:
Uri uri = new Uri(url, UriKind.Absolute);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
ServicePoint servicePoint = ServicePointManager.FindServicePoint(uri);
servicePoint.BindIPEndPointDelegate = new BindIPEndPoint(Bind);
//execute the request
response = (HttpWebResponse)request.GetResponse();
Stream receiveStream = response.GetResponseStream();
вам может понадобиться это:
private IPEndPoint Bind(ServicePoint servicePoint, IPEndPoint remoteEndPoint, int retryCount)
{
IPAddress address = IPAddress.Parse(GetHostIP());
return new IPEndPoint(address, 0);
}
Получить IP конкретного адаптера:
private string GetIPfromNetworkCard(string EthernetCardName)
{
string Ret = "";
foreach (NetworkInterface netif in NetworkInterface.GetAllNetworkInterfaces())
{
if (netif.Name == EthernetCardName)
{
IPInterfaceProperties properties = netif.GetIPProperties();
//foreach (IPAddressInformation unicast in properties.UnicastAddresses)
//{
// Select the first one...
Ret = properties.UnicastAddresses[0].Address.ToString();
break;
//}
}
}
return Ret;
}
Нет, невозможно использовать какие-либо классы C# - все они работают на слишком высоком уровне, чем на уровне TCP/IP (даже сокеты слишком высокого уровня). Стек Windows TCP/IP использует таблицу маршрутизации и метрики интерфейса, чтобы определить, какой интерфейс отправлять пакеты.
Вы можете увидеть, какой интерфейс, определенный в стеке TCP/IP Windows, имеет лучший маршрут (который он будет использовать для отправки пакета), вызвав функцию GetBestInterfaceEx ().
У бывшего работодателя мы пытались сделать что-то похожее, разделяя трафик на разные сетевые карты, привязывая сокет к IP-адресу карты, на которую мы хотели отправить трафик. Однако Windows будет отправлять трафик через NIC, который, по ее мнению, имеет лучший маршрут (NIC с IP-адресом, отличным от исходного). Это заняло немного царапин, прежде чем мы поняли, что происходит.
Так что если не делать что-то (возможно) с необработанными сокетами или libpcap (что будет насмешкой, вам придется создавать собственные обработчики TCP/IP и HTTP), вы не сможете сделать это в Windows.