К сожалению, стек используемых стандартных библиотечных модулей (urllib2, httplib, socket) несколько плохо спроектирован для этой цели - в ключевой момент операции HTTPConnection.connect
(в httplib) делегирует socket.create_connection
, что в свою очередь, между созданием экземпляра сокета sock
и вызовом sock.connect
нет никакой «зацепки», чтобы вставить sock.bind
непосредственно перед sock.connect
, то есть то, что вам нужно для установки исходного IP-адреса ( Я широко проповедую за то, что НЕ проектирую абстракции таким воздухонепроницаемым, чрезмерно инкапсулированным способом - я буду говорить об этом в OSCON в этот четверг под названием «Дзен и поддержание искусства абстракции» - но здесь ваша проблема как работать со стеком абстракций, которые были разработаны таким образом, вздох).
Когда вы сталкиваетесь с такими проблемами, у вас есть только два не очень хороших решения: либо скопируйте, вставьте и отредактируйте неправильно разработанный код, в который вам нужно поместить «зацепку», которой оригинальный дизайнер не воспользовался; или «обезьяна-патч» этот код. Ни то, ни другое ХОРОШО, но оба могут работать, так что, по крайней мере, давайте будем благодарны, что у нас есть такие варианты (с использованием открытого исходного кода и динамического языка). В этом случае, я думаю, я бы пошел на исправление обезьян (что плохо, но копирование и вставка кодирования еще хуже) - фрагмент кода, такой как:
import socket
true_socket = socket.socket
def bound_socket(*a, **k):
sock = true_socket(*a, **k)
sock.bind((sourceIP, 0))
return sock
socket.socket = bound_socket
В зависимости от ваших точных потребностей (вам нужно, чтобы все сокеты были привязаны к одному и тому же исходному IP-адресу, или ...?), Вы можете просто запустить это перед использованием urllib2
как обычно, или (конечно, более сложными способами) при необходимости запускайте его только для тех исходящих сокетов, которые вам НЕОБХОДИМО связать определенным образом (затем каждый раз восстанавливайте socket.socket = true_socket
, чтобы убрать путь с будущих сокетов, которые еще предстоит создать). Второй вариант добавляет свои сложности к правильной организации, поэтому я жду, чтобы вы выяснили, нужны ли вам такие сложности, прежде чем объяснять их все.
Хороший ответ AKX - это вариант альтернативы «копировать / вставить / редактировать», поэтому мне не нужно особо на этом разбираться - однако учтите, что он не совсем точно воспроизводит socket.create_connection
в методе connect
посмотрите исходный код здесь (в самом конце страницы) и решите, какие другие функции функции create_connection
вы, возможно, захотите включить в свою скопированную / вставленную / отредактированную версию, если решите перейти к этому маршрут.