Я хотел бы реализовать Twisted-сервер, который ожидает запросов XML и отправляет ответы XML в ответ:
<request type='type 01'><content>some request content</content></request>
<response type='type 01'><content>some response content</content></response>
<request type='type 02'><content>other request content</content></request>
<response type='type 02'><content>other response content</content></response>
Я создал Twisted client и server до, которые обменивались простыми строками и пытались распространить это на использование XML, но я не могу понять, как правильно настройте его.
client.py:
#!/usr/bin/env python
# encoding: utf-8
from twisted.internet import reactor
from twisted.internet.endpoints import TCP4ClientEndpoint, connectProtocol
from twisted.words.xish.domish import Element, IElement
from twisted.words.xish.xmlstream import XmlStream
class XMLClient(XmlStream):
def sendObject(self, obj):
if IElement.providedBy(obj):
print "[TX]: %s" % obj.toXml()
else:
print "[TX]: %s" % obj
self.send(obj)
def gotProtocol(p):
request = Element((None, 'request'))
request['type'] = 'type 01'
request.addElement('content').addContent('some request content')
p.sendObject(request)
request = Element((None, 'request'))
request['type'] = 'type 02'
request.addElement('content').addContent('other request content')
reactor.callLater(1, p.sendObject, request)
reactor.callLater(2, p.transport.loseConnection)
endpoint = TCP4ClientEndpoint(reactor, '127.0.0.1', 12345)
d = connectProtocol(endpoint, XMLClient())
d.addCallback(gotProtocol)
from twisted.python import log
d.addErrback(log.err)
reactor.run()
Как и в предыдущем основанном на строках подходе, клиент простаивает до CTRL + C. Как только я это сделаю, он привлечет некоторое/много вдохновения из примера Twisted XMPP.
server.py:
#!/usr/bin/env python
# encoding: utf-8
from twisted.internet import reactor
from twisted.internet.endpoints import TCP4ServerEndpoint
from twisted.words.xish.xmlstream import XmlStream, XmlStreamFactory
from twisted.words.xish.xmlstream import STREAM_CONNECTED_EVENT, STREAM_START_EVENT, STREAM_END_EVENT
REQUEST_CONTENT_EVENT = intern("//request/content")
class XMLServer(XmlStream):
def __init__(self):
XmlStream.__init__(self)
self.addObserver(STREAM_CONNECTED_EVENT, self.onConnected)
self.addObserver(STREAM_START_EVENT, self.onRequest)
self.addObserver(STREAM_END_EVENT, self.onDisconnected)
self.addObserver(REQUEST_CONTENT_EVENT, self.onRequestContent)
def onConnected(self, xs):
print 'onConnected(...)'
def onDisconnected(self, xs):
print 'onDisconnected(...)'
def onRequest(self, xs):
print 'onRequest(...)'
def onRequestContent(self, xs):
print 'onRequestContent(...)'
class XMLServerFactory(XmlStreamFactory):
protocol = XMLServer
endpoint = TCP4ServerEndpoint(reactor, 12345, interface='127.0.0.1')
endpoint.listen(XMLServerFactory())
reactor.run()
client.py
вывод:
TX [127.0.0.1]: <request type='type 01'><content>some request content</content></request>
TX [127.0.0.1]: <request type='type 02'><content>other request content</content></request>
server.py
вывод:
onConnected(...)
onRequest(...)
onDisconnected(...)
Мои вопросы:
- Как подписаться на событие, запущенное, когда сервер сталкивается с определенным тегом XML? Запрос
//request/content
XPath кажется мне удобным, ноonRequestContent(...)
не вызван: - ( - Является ли подклассом
XmlStream
иXmlStreamFactory
разумным подходом вообще? Чувство странно, потому чтоXMLServer
подписывается на события, отправленные его собственным базовым классом, а затем передается сам (?) Какxs
параметр?!? Должен ли я сделатьXMLServer
обычный класс и иметь объектXmlStream
как член класса? Существует ли канонический подход? - Как добавить обработчик ошибок на сервер, например
addErrback(...)
в клиенте? Я беспокоюсь, что исключения проглатываются (раньше было), но я не вижу, где получитьDeferred
, чтобы прикрепить его к... - Почему сервер по умолчанию закрывает соединение после первого запроса? Я вижу
XmlStream.onDocumentEnd(...)
вызовloseConnection()
; Я мог бы переопределить этот метод, но мне интересно, есть ли причина закрытия, которую я не вижу. Разве это не "нормальный" подход, чтобы оставить соединение открытым до тех пор, пока не будет выполнено все необходимые коммуникации на данный момент?
Я надеюсь, что этот пост не считается слишком конкретным; говорящий XML по сети является обычным явлением, но, несмотря на поиск полтора дня, я не смог найти примеры Twisted XML-сервера. Может быть, мне удастся превратить это в Jumpstart для любого в будущем с похожими вопросами...