【问题标题】:python networking: asynchat handshakepython网络:异步握手
【发布时间】:2011-12-06 02:53:07
【问题描述】:

我正在使用 python asynchat 来实现网络协议。 在连接时,我需要发送一个命令,然后服务器通过会话进行应答。

我的主要问题是我需要等到收到会话响应。但不确定如何实现这一点。我应该使用 socket.recv 进行连接设置吗?是个好主意吗?

【问题讨论】:

  • 您可以使用select 包吗?或者,如果您使用阻塞套接字,只需执行 recv 它将阻塞,直到有内容可读取。

标签: python networking asynchronous asyncore


【解决方案1】:

当使用异步技术编写网络应用程序时,您等待在某处记录您的状态,然后让主循环继续。在未来的某个时间,您正在等待的数据将变得可用,主循环将通知您这一事实,您可以将新数据与记录的状态结合起来以完成您正在处理的任何任务。根据具体的任务,您可能需要多次经历此循环才能真正完成任务。

无论您使用什么异步系统,这些想法基本相同。但是,Twisteda vastly superior systemasynchat,所以我不打算解释任何 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 个,客户端将打印它们(然后无限期地挂起,因为我在该协议中没有实现进一步的逻辑)。

【讨论】:

  • 非常适合您的示例,我知道如何编写 asynchat 解决方案。无论如何,我想使用 twisted 但是,我正在重写一个 python activemq 开源驱动程序。我想要最低要求。谢谢!
  • 拥有最低要求意味着您要付出更高的开发成本来换取某种安装便利性——安装的东西更少,或者安装的占地面积更小,等等。不过,安装很容易——它经常是自动化的,以便实际上是免费的,而且 Twisted 已经安装在数百万台计算机上(例如,大约 1/3 的 Debian 安装已经安装了它)。安装的占用空间可能是一个问题,但仅限于极小的设备,即使这些设备现在也有很多空间(8GB 闪存的成本是多少?)。此外,Python 本身比 Twisted 还要大。
  • 只是让你知道,我也喜欢扭曲 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多