Как сокет знает, какой контроллер сетевого интерфейса использовать?

Если на компьютере установлено несколько сетевых карт, все они подключены к разным сетям и работают нормально, когда мы открываем сокет, как ОС определяет, какой сетевой адаптер использовать с этим сокетом? Позволяет ли API сокетов явно указывать NIC, который будет использоваться?

Ответ 1

Я не знаю, почему я был включен в предложение по редактированию, когда я даже не имел отношения к этому вопросу. У меня тоже было подобное предложение по редактированию и раньше... может быть какая-то ошибка/проблема.

(Если вы склонны голосовать "вверх", ответ @Shtéf заслуживает его больше, чем мой.)

Это зависит от того, подключаетесь вы или нет.

Если вы привязываете, вы можете привязать к определенному IP-адресу, соответствующему одному из интерфейсов машины, или вы можете привязать к 0.0.0.0, и в этом случае сокет будет прослушивать все интерфейсы.

Если вы подключите несвязанный сокет, то таблицы маршрутизации машины вместе с IP-адресом назначения будут определять, на каком интерфейсе будет отправлен запрос на подключение.

Можно связать сокет и подключить его. В этом случае сокет останется связанным согласно вызову связывания, когда это делает соединение. (Спасибо @RemyLebeau за указание на это.)

Ответ 2

Я пишу это с точки зрения Linux, но я полагаю, что это применимо повсюду.

Решение принимается при привязке сокета. Когда вызывается bind, указанный вами адрес определяет интерфейс, который будет прослушивать сокет. (Или даже все интерфейсы.)

Даже если вы не используете bind, это происходит неявно, когда вы connect. Пункт назначения просматривается в таблице маршрутов, которая должна содержать маршрут к целевой сети. Маршрут также содержит интерфейс для использования и может дополнительно указать адрес источника. Если адрес источника не указан, выполняется первичный адрес интерфейса.

Фактически вы можете использовать bind вместе с connect, чтобы заставить исходящее соединение использовать определенный адрес и порт. Сокет должен всегда иметь эти два бита информации, поэтому даже если вы этого не сделаете, используется первичный адрес и выбран случайный порт.

Ответ 3

Я не уверен, какой метод является лучшим, но есть альтернативная теория для подхода bind() - before-connect(), который представил Штеф. Он должен использовать setsockopt() с SO_BINDTODEVICE. См.: http://codingrelic.geekhold.com/2009/10/code-snippet-sobindtodevice.html