2014-11-20 3 views
2

Я реализовал серверную программу с использованием Twisted. Я использую basic.lineReceiver со способом dataReceived для получения данных от нескольких клиентов. Кроме того, я использую protocol.ServerFactory для отслеживания подключенных клиентов. Сервер отправляет некоторые команды каждому подключенному клиенту. На основе ответа, который сервер получает от каждого клиента, он (сервер) должен выполнять некоторые задачи. Таким образом, лучшим решением, которое пришло мне в голову, было создание буфера для принятых сообщений в виде списка python, и каждый раз, когда функции на стороне сервера хотят знать ответ от клиента, они обращаются к последнему элементу списка буферов (этого клиента). Этот подход оказался ненадежным. Первая проблема заключается в том, что, поскольку используется потоковая передача TCP, иногда происходит слияние сообщений (для этого я могу использовать разделитель). Во-вторых, полученные сообщения иногда не в соответствующей последовательности. В-третьих, сетевое общение кажется слишком медленным, поскольку, когда сервер изначально пытается получить доступ к последнему элементу буферизованного списка, список пуст (это показывает, что последние сообщения в буфере могут быть не ответом на последний отправленный команд). Не могли бы вы рассказать мне, что является наилучшей позицией для использования dataReceived или ее эквивалентов в вышеупомянутой проблеме? заранее спасибо.Как использовать dataReceived в Twisted?

EDIT 1: ответа- Пока я принимаю @ ответ Жан-Поль Калдерон со времени я, конечно, узнал от него, я хотел бы добавить, что в моих собственных исследований документации витыми, я узнал, что для того, чтобы избежать задержек в коммуникаций сервера, следует использовать return в конце функций dataReceived() или lineReceived(), и это решило часть моей проблемы. Остальные были объяснены в ответе.

ответ

5

Я реализовал серверную программу с использованием Twisted. Я использую basic.lineReceiver с методом dataReceived для получения данных от нескольких клиентов.

Это ошибка, которая, к сожалению, распространена в результате ошибочного использования наследования во многих реализациях протокола Twisted в качестве механизма для создания более совершенного поведения. Когда вы используете twisted.protocols.basic.LineReceiver, ответный вызов dataReceived - это не для вас. LineReceiver.dataReceived является деталь реализации из LineReceiver. Обратный вызов для вас - LineReceiver.lineReceived. LineReceiver.dataReceived похоже, что это может быть для вас - оно не начинается с подчеркивания или чего-то еще, но это не так. dataReceived - это то, как LineReceiver получает информацию от своего транспорта. Это один из общедоступных методов IProtocol - интерфейс между транспортом и протоколом, интерпретирующий данные, полученные над этим транспортом. Да, я просто сказал «общественный метод». Проблема в том, что это публично в интересах кто-то еще. Это сбивает с толку и, возможно, не сообщается, как могло бы быть. Несомненно, именно поэтому это Frequently Asked Question.

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

Почему это происходит. Использование dataReceived. LineReceiver уже реализует синтаксический анализ на основе разделителей. Вот почему он называется «линейным» приемником - он получает линии, разделенные разделителем. Если вы переопределите lineReceived вместо dataReceived, тогда вы будете называть, какая каждая полученная строка, независимо от того, как TCP разбивает вещи или разбивает их вместе.

Во-вторых, полученные сообщения иногда не в соответствующей последовательности.

TCP - это надежный, заказываемый, ориентированный на поток транспорт. «Ordered» означает, что байты поступают в том же порядке, в котором они отправлены. Иными словами, если вам write("x"); write("y") гарантировано, что получатель получит «x», прежде чем они получат «y» (они могут принимать «x» и «y» в том же вызове до recv(), но если они это сделают, данные будут определенно «xy», а не «yx», или они могут получить два байта в двух вызовах до recv(), и если они это сделают, то первые recv() будут определенно «x», а вторая определенно будет «y», а не наоборот вокруг).

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

Другая возможность заключается в том, что вы говорите о порядке, в котором данные поступают через несколько отдельных TCP-соединений. TCP заказывается только по одному соединению. Если у вас есть два подключения, очень мало (если есть) гарантий относительно порядка, в котором данные будут поступать по ним.

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

Что определяет «слишком медленно»? Сеть работает так же быстро, как сеть. Если это недостаточно быстро для вас, найдите более толстый кусок меди. Похоже, что вы на самом деле имеете в виду, что ваш сервер иногда ожидает, что данные будут получены до того, как эти данные поступят. Это не означает, что сеть слишком медленная, но это означает, что ваш сервер не является должным образом управляемый событиями. Если вы проверяете буфер и не находите информацию, которую вы ожидали, это потому, что вы проверили ее до появления события, которое информирует вас о прибытии этой информации. Вот почему у Twisted есть все эти методы обратного вызова - dataReceived, lineReceived, connectionLost и т. Д. Когда вызывается lineReceived, это уведомление о событии, в котором сообщается, что прямо сейчас произошло что-то, что привело к тому, что линия была доступна (и, lineReceived принимает один аргумент - объект, представляющий линию, которая теперь доступна).

Если у вас есть код, предназначенный для запуска, когда линия прибыла, подумайте о том, чтобы включить этот код в реализацию метода lineReceived. Таким образом, когда он запускается (в ответ на полученную строку), вы можете быть на 100% уверены, что у вас есть линия для работы. Вы также можете быть уверены, что он будет работать как можно скорее (как только линия придет), но не раньше.

+0

Благодарим вас за ответ. Что касается порядка полученных сообщений, если я использую библиотеку сокетов python на стороне клиента, записывая socket.recv() или socket.send, может ли это привести к тому, что соединение не будет TCP? – user823743

+0

Если вы используете 'socket.socket() '(без аргументов) для создания сокета, это сокет TCP (и может использоваться только для соединений TCP). Кроме того, 'reactor.listenTCP' создает сервер, который может принимать только TCP-соединения. –

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