2011-12-06 2 views
1

私はネットワークプロトコルを実装するためにpython asynchatを使用しています。 接続時には、セッションでサーバーの応答とコマンドを送信する必要があります。python networking:asynchatハンドシェイク

私の主な問題は、私がセッション応答を得るまで待つ必要があることです。これを実装する方法は不明です。接続設定にsocket.recvを使用する必要がありますか?良いアイデアですか?

+0

[select](http://docs.python.org/library/select.html)パッケージを使用できますか?または、ブロッキングソケットを使用している場合は、単に 'recv'を実行して、何かが読み込まれるまでブロックします。 –

答えて

3

非同期技術を使用してネットワークアプリケーションを作成する場合は、を待ってから、メインループを続行してください。将来的には、待機しているデータが利用可能になり、メインループがその旨を通知し、記録した状態と新しいデータを組み合わせて、作業中のタスクを完了させることができます。特定のタスクに応じて、実際にタスクを実行する前にこのサイクルを何度も繰り返す必要があります。

これらのアイデアは、使用している非同期システムに関係なく、基本的に同じです。しかし、Twisteda vastly superior systemからasynchatまでですので、私はasynchatの詳細を説明するつもりはありません。代わりに、ここでツイスト使用して、あなたは約求めているもののようなものを行う例です:これはどのように動作するかを確認するには

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を送り返すと、クライアントはそれらを印刷します(そして、そのプロトコルではロジックを実装していないので、無期限にハングアップします)。

+0

本当に有益! :) – jathanism

+0

あなたの例で素晴らしい私はasynchatソリューションを記述する方法を知っています。とにかく私はツイストを使用すると思ったが、私はpython activemq opensourceドライバを書き換えている。私は最小のrequirimentsをしたい。ありがとう! – llazzaro

+0

最小限の要件を満たすことで、インストールの容易性や設置面積の縮小など、インストールの利便性を高め、開発コストを高くすることができます。インストールは簡単ですが、頻繁に自動化されていますので、すでに数百万台のコンピュータにインストールされています(例えば、すべてのDebianインストールの約1/3は既にそれを持っています)。インストールされたフットプリントは懸念されるかもしれませんが、極端に小さなデバイスでしか使用できません。最近では8GBのフラッシュにはいくらかかるのでしょうか?さらに、Python自体はTwistedより大きい。 –

関連する問題