Выберите одно из многих интернет-подключений для приложения
У меня есть компьютер с несколькими интернет-соединениями. LAN, WLAN, WiFi или 3G. Все они активны, и машина может использовать любой из них.
Теперь я хочу сообщить своему приложению использовать одно из доступных подключений. Например, я хочу сказать, что мое приложение использует только WiFi, в то время как другое программное обеспечение может использовать что-то еще.
В моем приложении С# я использую классы типа HttpWebRequest
и HttpWebResponse
.
Возможно ли это?
Ответы
Ответ 1
Это несколько расширенная функциональность, которая абстрагируется как HttpWebRequest, WebRequest, WebClient, так и т.п. Вы можете, однако, сделать это, используя TcpClient
(используя конструктор Socket.Bind.
Используйте метод Bind, если вам нужно использовать определенную локальную конечную точку. Вы должны позвонить Bind, чтобы вызвать метод Listen. Вам не нужно вызывать Bind перед использованием метода Connect, если вам не нужна конкретная локальная конечная точка.
Привязать к локальной конечной точке для интерфейса, который вы хотите использовать. Если ваш локальный компьютер имеет IP-адрес 192.168.0.10 для WiFi-адреса, то использование этой локальной конечной точки заставит сокеты использовать этот интерфейс. Значение по умолчанию является unbound (действительно 0.0.0.0), которое сообщает сетевому стеку автоматически разрешать интерфейс, который вы хотите обойти.
Вот пример кода на основе комментария Andrew. Обратите внимание, что указание 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("stackoverflow.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("stackoverflow.com", 80);
}
}
}
Ответ 2
См. эту запись в 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;
}
Ответ 3
Вы можете определенно сделать это:
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;
}
Ответ 4
Нет, это невозможно с использованием каких-либо классов С# - все они работают на слишком высоком уровне, что на уровне TCP/IP (четные сокеты слишком высоки уровня). Стек TCP/IP Windows использует таблицу маршрутизации и метрики интерфейса для определения интерфейса для отправки пакетов.
Вы можете узнать, какой интерфейс Windows TCP/IP-стека определил, имеет лучший маршрут (который он будет использовать для отправки пакета), вызывая GetBestInterfaceEx().
У бывшего работодателя мы попытались сделать что-то подобное, разделив трафик на разные сетевые карты, привязав сокет к IP-адресу карты, на которую мы хотели отправить трафик. Однако Windows отправляет трафик из сетевого адаптера, который он видел, имеет лучший маршрут (сетевой адаптер с другим IP-адресом, чем источник). Это немного поцарапало голову, прежде чем мы поняли, что происходит.
Нечего делать (возможно) с сырыми сокетами или libpcap (которые были бы смешными, вам пришлось бы создавать собственные обработчики TCP/IP и HTTP), вы не можете сделать это в Windows.