2010-04-09 3 views
4

Я пытаюсь написать код Python, который установит невидимое реле между двумя сокетами TCP. Мой метод состоит в том, чтобы настроить два потока, каждый из которых считывает и впоследствии записывает 1kb данных за раз в определенном направлении (то есть 1 поток для A-B, 1 поток для B-A).Как правильно передать TCP-трафик между сокетами?

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

Я думаю, что это связано с тем, что, когда я заканчиваю выполнение чтения на сокете А, программа, работающая там, считает, что ее данные уже достигли Б, когда на самом деле я - коварный человек посередине - еще не отправил это к B. В ситуации, когда B не готов к получению данных (в течение которых блокирует send()), мы находимся в состоянии, когда A считает, что оно успешно отправило данные в B, но я все еще держу данные , ожидая вызова send(). Я думаю, что это причина различия в поведении, которое я нашел в некоторых приложениях, используя мой текущий ретрансляционный код. Я что-то пропустил, или это звучит правильно?

Если это так, мой настоящий вопрос: есть ли способ решить эту проблему? Можно ли читать только сокета А, когда мы знаем, что B готов к приему данных? Или есть другой метод, который я могу использовать для создания действительно «невидимого» двухстороннего реле между [уже открытыми установленными] TCP-сокетами?

+0

Вы говорите, что используете TCP-сокеты, но вы прокомментировали, что используете сокеты Unix. Вы действительно используете сокеты домена Unix? – JimB

+0

Да, перепутали два разных вопроса. Я отметил правильный ответ ниже, как тот, который отвечает на вопрос, который я фактически разместил. Все еще застрял в моей проблеме ретрансляции сокетов Unix, хотя ... :( – flukes1

+0

Как вы справляетесь с завершением соединения?Знаете ли вы, что соединение может быть закрыто в направлении «A -> B», но все же должно быть открыто в направлении «B -> A»? Правильно ли передается ваш прокси-сервер? – caf

ответ

5

Можно читать только из гнезда А когда мы знаем, что Б готов получить данные?

Sure: использовать select.select на обоих сокетов А и В (если она возвращает говоря только один из них готов, использовать его на другой), и только для чтения от А и писать B, когда вы знаете, что они» оба готовы. Например:

import select 

def fromAtoB(A, B): 
    r, w = select.select([A], [B], []) 
    if not r: select.select([A], [], []) 
    elif not w: select.select([], [B], []) 
    B.sendall(A.recv(4096)) 
+0

Я изменил свой код, чтобы использовать его, но исходная проблема все еще существует - приложение, которое я тестирую, по-прежнему ведет себя по-другому с реле на месте. Кроме того, включение этого цикла while приводит к тому, что Python использует множество циклов процессора. Следует отметить, что данные отправляются с довольно высокой пропускной способностью. Если у вас есть другие предложения, я бы с удовольствием их услышал. – flukes1

+0

Я исправил проблему с процессором, но до сих пор не купил на мою оригинальную проблему. Вот мой код: http://pastie.org/910900 – flukes1

+0

(1) Я удивлен, услышав о высоком потреблении процессора, поскольку мой код не тратит до тех пор, пока данные не будут готовы - возможно, данные отправляются в крошечные пакеты , но даже тогда, если вы хотите очень быстро его передать, трудно подумать, как улучшить это (если вы не захотите добавить, возможно, очень длинные задержки). (2) Я не удивлен, что это имеет мало общего с вашей реальной проблемой - я просто ответил на ваш вопрос, который я цитировал, о чтении из А только тогда, когда мы знаем, что Б готов к написанию; различия в поведении могут быть связаны с проверкой A его сверстником, которую вы не можете подделать. –

1

Я не думаю, что это может быть вашей проблемой.

В общем случае приложение-отправитель не может определить, когда приложение-получатель фактически вызывает recv() для чтения данных: отправитель() может быть выполнен, но реализация TCP в исходной & целевых ОС будет выполнять буферизация, управление потоком, повторная передача и т. д.

Даже без вашего реле в середине, для того, чтобы «рассмотреть свои данные, которые уже достигли B», это получить ответ от B, говорящий «да, я понял".

1

Возможно, приложение, к которому выполняется проксирование, плохо написано.

Например, если я звоню recv(fd, buf, 4096, 0); Я не обещал 4096 байт. Система прилагает все усилия для ее обеспечения.

Если 1k не кратно размеру вашего приложения recv или send, а приложение будет разбито, то группировка данных, отправленных в 1k-блоки, приведет к поломке приложения.

+0

Вижу. Есть ли способ обойти это? – flukes1

+0

Поощряйте писателя приложения писать лучшее программное обеспечение. Если вы пытаетесь создать общий прокси-сервер, то нет, нет. Если это для конкретного приложения, попробуйте подражать размеру send и recv, используемому клиентом и сервером. – rescrv

Смежные вопросы