Выберите одно из многих подключений к Интернету для приложения - PullRequest
15 голосов
/ 28 декабря 2010

У меня есть компьютер с несколькими различными подключениями к Интернету.LAN, WLAN, WiFi или 3G.Все они активны, и машина может использовать любой из них.

Теперь я хочу указать моему приложению использовать одно из доступных соединений.Например, я хочу указать моему приложению использовать только WiFi, в то время как другое программное обеспечение может использовать что-то другое.

В моем приложении на c # я использую классы типа HttpWebRequest и HttpWebResponse.

Возможно ли это вообще?

Ответы [ 4 ]

19 голосов
/ 28 декабря 2010

Это несколько продвинутая функциональность, которая абстрагируется как 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("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);
        }
    }
}
10 голосов
/ 01 марта 2011

См. Эту запись блога 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;
}
1 голос
/ 26 апреля 2017

Вы определенно можете сделать это:

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;
    }
0 голосов
/ 28 декабря 2010

Нет, невозможно использовать какие-либо классы C # - все они работают на слишком высоком уровне, чем на уровне TCP / IP (четные сокеты слишком высокого уровня). Стек Windows TCP / IP использует таблицу маршрутизации и метрики интерфейса, чтобы определить, какой интерфейс отправлять пакеты.

Вы можете увидеть, какой интерфейс для стека Windows TCP / IP определил лучший маршрут (который он будет использовать для отправки пакета), вызвав GetBestInterfaceEx () .

У бывшего работодателя мы пытались сделать что-то похожее, разделив трафик на разные сетевые карты, привязав сокет к IP-адресу карты, на которую мы хотели отправить трафик. Однако Windows будет отправлять трафик через NIC, который, по ее мнению, имеет лучший маршрут (NIC с IP-адресом, отличным от исходного). Это заняло немного царапин, прежде чем мы поняли, что происходит.

Так что если не делать что-то (возможно) с необработанными сокетами или libpcap (что будет насмешкой, вам придется создавать свои собственные обработчики TCP / IP и HTTP), вы не сможете сделать это в Windows.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...