Python Networking: Asynchat рукопожатие

1

Я использую python asynchat для реализации сетевого протокола. Во время соединения мне нужно отправить команду и ответ сервера с сеансом.

Моя основная проблема заключается в том, что мне нужно подождать, пока не получу ответ сеанса. но не уверен, как это реализовать. следует ли использовать socket.recv для настройки соединения? это хорошая идея?

  • 0
    Вы можете использовать пакет выбора ? Или, если вы используете блокирующие сокеты, просто сделайте recv и он будет блокироваться, пока не будет что почитать.
Теги:
networking
asynchronous
asyncore

1 ответ

3
Лучший ответ

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

Эти идеи в основном одинаковы независимо от того, какую асинхронную систему вы используете. Однако Twisted - это превосходная система для асинчат, поэтому я не буду пытаться объяснить какие-либо детали асинчатча. Вместо этого, вот пример, который делает то, о чем вы спрашиваете, используя Twisted:

from twisted.internet.defer import Deferred
from twisted.internet.protocol import Protocol, Factory
from twisted.internet.endpoints import TCP4ClientEndpoint
from twisted.internet import reactor

# Stream-oriented connections like TCP are handled by an instance 
# of a Protocol subclass
class SomeKindOfClient(Protocol):

     # When a new connection is established, the first thing that
     # happens is this method is called.
     def connectionMade(self):
         # self.transport is set by the superclass, and lets us 
         # send data over the connection
         self.transport.write("GREETING")

         # a Deferred is a generic, composable API for specifying
         # callbacks
         self.greetingComplete = Deferred()

         # Here some local state
         self._buffer = ""

     # Whenever bytes arrive on the TCP connection, they're passed
     # to this method
     def dataReceived(self, bytes):

         # Incorportate the network event data into our local state.
         #  This kind of buffering is always necessary with TCP, because
         # there no guarantees about how many bytes will be delivered
         # at once (except that it will be at least 1), regardless of
         # the size of the send() the peer did.
         self._buffer += bytes

         # Figure out if we're done - let say the server response is 32
         # bytes of something
         if len(self._buffer) >= 32:
             # Deliver it to whomever is waiting, by way of the Deferred
             # object
             greeting, self._buffer = self._buffer[:32], self._buffer[32:]
             complete = self.greetingComplete
             self.greetingComplete = None
             complete.callback(greeting)

         # Otherwise we'll keep waiting until dataReceived is called again
         # and we have enough bytes.


# One of the normal ways to create a new client connection
f = Factory()
f.protocol = SomeKindOfClient
e = TCP4ClientEndpoint(reactor, "somehost", 1234)

# Connect returns one of those Deferreds - letting us specify a function
# to call when the connection is established.  The implementation of
# connect is also doing basically the same kind of thing as you're asking
# about.
d = e.connect(f)

# Execution continues to this point before the connection has been
# established.  Define a function to use as a callback when the connection
# does get established.
def connected(proto):
    # proto is an instance of SomeKindOfClient.  It has the 
    # greetingComplete attribute, which we'll attach a callback to so we
    # can "wait" for the greeting to be complete.
    d = proto.greetingComplete

    def gotGreeting(greeting):
        # Note that this is really the core of the answer.  This function
        # is called *only* once the protocol has decided it has received
        # some necessary data from the server.  If you were waiting for a
        # session identifier of some sort, this is where you might get it
        # and be able to proceed with the remainder of your application
        # logic.
        print "Greeting arrived", repr(greeting)

    # addCallback is how you hook a callback up to a Deferred - now
    # gotGreeting will be called when d "fires" - ie, when its callback
    # method is invoked by the dataReceived implementation above.
    d.addCallback(gotGreeting)

# And do the same kind of thing to the Deferred we got from 
# TCP4ClientEndpoint.connect
d.addCallback(connected)

# Start the main loop so network events can be processed
reactor.run()

Чтобы узнать, как это происходит, вы можете запустить простой сервер (например, nc -l 1234) и указать на него клиента. Вы увидите приветствие, и вы можете отправить несколько байтов обратно. После того, как вы отправите назад 30, клиент распечатает их (а затем повесить на неопределенное время, потому что я не реализовал в этом протоколе больше никакой логики).

  • 0
    Действительно информативно! :)
  • 0
    отлично с вашим примером я знаю, как написать решение asynchat. В любом случае, я подумал использовать Twisted, но я переписываю драйвер с открытым исходным кодом Python activemq. Я хочу минимальные требования. Спасибо!
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню