Как туннелировать TCP по надежному UDP?

Короткий ответ Обход правила оценки по умолчанию и делают не , оценивают выражение (символ или s-exp), передавая его функции точно, как введено.

Длинный Ответ: Правило

Оценки По умолчанию, Когда постоянный клиент (я приеду в тот позже) функция будет вызвана, все аргументы, передало ей, оценены. Это означает, что можно записать это:

(* (+ a 2)
   3)

, Который в свою очередь оценивает (+ a 2) путем оценки a и 2. Значение символа a ищется в текущем наборе привязки переменной, и затем заменяется. Скажите a, в настоящее время связывается со значением 3:

(let ((a 3))
  (* (+ a 2)
     3))

Мы добрались бы (+ 3 2), + тогда вызывается на 3 и 2 получения 5. Наша исходная форма теперь (* 5 3) получение 15.

Уже Объясняют quote!

Хорошо. Как замечено выше, все аргументы функции оценены, поэтому если требуется передать символ a и не его значение, Вы не хотите оценивать его. Символы Lisp могут удвоиться и как их значения и как маркеры, где Вы на других языках использовали бы строки, такие как ключи к хэш-таблицам.

Это - то, где quote входит. Скажите, что Вы хотите вывести выделения ресурса на печать из приложения Python, а скорее сделать графическое изображение в Lisp. Имейте свое приложение Python, делают что-то вроде этого:

print("'(")
while allocating:
    if random.random() > 0.5:
        print(f"(allocate {random.randint(0, 20)})")
    else:
        print(f"(free {random.randint(0, 20)})")
    ...
print(")")

Предоставление Вас произвело сходство с этим (немного украшенный):

'((allocate 3)
  (allocate 7)
  (free 14)
  (allocate 19)
  ...)

Помнят то, что я сказал [приблизительно 1 120] ("галочка"), вызывающая правило по умолчанию не применяться? Хороший. То, что иначе произошло бы, - то, что значения [1 121] и free ищутся, и мы не хотим это. В нашем Lisp мы хотим сделать:

(dolist (entry allocation-log)
  (case (first entry)
    (allocate (plot-allocation (second entry)))
    (free (plot-free (second entry)))))

Для данных, данных выше, следующая последовательность вызовов функции была бы сделана:

(plot-allocation 3)
(plot-allocation 7)
(plot-free 14)
(plot-allocation 19)

, Но Что относительно [1 123]?

ну, иногда Вы делаете , хотят оценить аргументы. Скажите, что у Вас есть изящная функция, управляющая числом и строкой и возвращающая список получающегося... вещи. Давайте сделаем неудачное начало:

(defun mess-with (number string)
  '(value-of-number (1+ number) something-with-string (length string)))

Lisp> (mess-with 20 "foo")
(VALUE-OF-NUMBER (1+ NUMBER) SOMETHING-WITH-STRING (LENGTH STRING))

Эй! Это не то, что мы хотели. Мы хотим к [1 142] выборочно , оценивают некоторые аргументы и оставляют другие как символы. Попробуйте № 2!

(defun mess-with (number string)
  (list 'value-of-number (1+ number) 'something-with-string (length string)))

Lisp> (mess-with 20 "foo")
(VALUE-OF-NUMBER 21 SOMETHING-WITH-STRING 3)

Не Всего quote, Но и backquote

Намного лучше! Инцидентным образом этот шаблон так распространен в (главным образом) макросах, что существует специальный синтаксис для того, чтобы сделать просто это. Одинарная левая кавычка:

(defun mess-with (number string)
  `(value-of-number ,(1+ number) something-with-string ,(length string)))

Это похоже на использование quote, но с опцией явно оценить некоторые аргументы путем добавления префикса их запятую. Результат эквивалентен использованию list, но если Вы генерируете код от макроса, Вы часто только хотите оценить мелкие детали возвращенного кода, таким образом, одинарная левая кавычка больше подходит. Для более коротких списков, list может быть более читаемым.

Эй, Вы Забыли [приблизительно 1 129]!

Так, где это оставляет нас? О, право, что делает quote на самом деле, делает? Это просто возвращает свой неоцененный аргумент (аргументы)! Помните то, что я сказал в начале о регулярных функциях? Оказывается, что для некоторых операторов/функций нужно к [1 143] не , оценивают их аргументы. Такой, как будто - Вы еще не хотели бы ответвление быть оцененными, если бы оно не было взято, правильно? Так называемый специальные операторы , вместе с макросами, работают как этот. Специальные операторы являются также "аксиомой" языка - минимального ряда правил - на который можно реализовать остальную часть Lisp путем объединения их вместе по-разному.

Назад к [1 131], хотя:

Lisp> (quote spiffy-symbol)
SPIFFY-SYMBOL

Lisp> 'spiffy-symbol ; ' is just a shorthand ("reader macro"), as shown above
SPIFFY-SYMBOL

Выдерживают сравнение с (на языке Common LISP Стального Банка):

Lisp> spiffy-symbol
debugger invoked on a UNBOUND-VARIABLE in thread #:
  The variable SPIFFY-SYMBOL is unbound.

Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
  0: [ABORT] Exit debugger, returning to top level.

(SB-INT:SIMPLE-EVAL-IN-LEXENV SPIFFY-SYMBOL #)
0] 

, поскольку нет никакого spiffy-symbol в текущей области!

Подведение Итогов

quote, backquote (с запятой), и list является некоторыми инструментами, которые Вы используете для создания списков, которые не являются только списками значений, но и поскольку Вы замеченный можете использоваться в качестве легкого веса (никакая потребность определить struct) структуры данных!

, Если Вы хотите узнать больше, я рекомендую книге Peter Seibel Практический язык Common LISP для практического подхода к изучению Lisp, если Вы уже в программирование в целом. В конечном счете на Вашей поездке Lisp, Вы начнете использовать пакеты также. Ron Garret Руководство Идиота по Пакетам языка Common LISP даст Вам хорошее объяснение тех.

Счастливое взламывание!

7
задан bmargulies 14 December 2009 в 14:30
поделиться

3 ответа

Самый эффективный способ - это когда две конечные точки напрямую связываются друг с другом. Если они взаимодействуют с разными протоколами, вам понадобится хотя бы один прокси / шлюз / конвертер трафика / что угодно. В этом случае невозможно обойтись без двух преобразователей, поскольку теперь у вас задействованы 3 части: клиент конечной точки, сетевой трафик, сервер конечной точки. Я не понимаю, как вы могли бы сделать его более эффективным в данных обстоятельствах.

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

0
ответ дан 7 December 2019 в 03:16
поделиться

есть несколько готовых к использованию вариантов:

  • OpenVPN : туннелирует IP- или Ethernet-кадры поверх UDP
  • Teredo : туннелирует IPv6 поверх UDPv4 управляет как прохождением NAT, так и полной совместимостью с IPv6
  • UDT : нестандартный, надежный, высокопроизводительный, мульти-транспортный, TCP-подобный протокол поверх UDP. При желании вы можете управлять обходом NAT, а затем принимать его оттуда
9
ответ дан 7 December 2019 в 03:16
поделиться

You're going to have to communicate the loss of the client TCP connection to the server side across your UDP tunnel (and the opposite, if the server should happen to close the connection first).

Otherwise, quite apart from the fact that the HTTP server doesn't know the client has disconnected, you will be leaking connections on the side that didn't initiate the connection closure.

One way to do this would be to reserve a special value of your 32 bit connection ID field - say 0x00000000 or 0xffffffff - as representing a control packet rather than connection data. Following that is another 4-byte field representing a connection ID, and following that is an opcode field. The first opcode you could define is "Connection terminated".

  • If your client-side of the tunnel detects that the client application has closed its TCP connection, it sends a Connection-Terminated packet for the corresponding connection ID over the tunnel;
  • If your client-side of the tunnel gets a "Connection terminated" opcode from the server side, then it closes its connection with the client application;

and similar for the server-side of the tunnel.

0
ответ дан 7 December 2019 в 03:16
поделиться