Pythonネットワーキング:Asynchatの握手
-
28-10-2019 - |
質問
Python Asynchatを使用して、ネットワークプロトコルを実装しています。接続時には、セッションでコマンドとサーバーの回答を送信する必要があります。
私の主な問題は、セッションの応答が得られるまで待つ必要があることです。しかし、これを実装する方法がわかりません。接続セットアップにSocket.Recvを使用する必要がありますか?良い考えですか?
解決
非同期テクニックを使用してネットワークアプリケーションを作成するとき、あなたは 待つ 状態をどこかに記録し、メインループを継続することにより。将来の時期に、あなたが待ち望んでいるデータが利用可能になり、メインループはその事実を通知し、新しいデータを記録された状態と組み合わせて、取り組んでいるタスクを完了することができます。特定のタスクに応じて、タスクが実際に完了する前に、このサイクルを何度も通過する必要がある場合があります。
これらのアイデアは、あなたが使用している非同期システムに関係なく、基本的に同じです。でも、 ねじれた は 非常に優れたシステム に asynchat, 、ですから、私はAsynchatの詳細を説明しようとはしません。代わりに、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's 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's 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's 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を返送すると、クライアントはそれらを印刷します(そして、そのプロトコルにさらなるロジックを実装しなかったため、無期限にぶらぶらします)。
所属していません StackOverflow