与 TCPServer 保持另一个持久的 TCP 连接

Posted

技术标签:

【中文标题】与 TCPServer 保持另一个持久的 TCP 连接【英文标题】:Maintaining another persistent TCP connection with TCPServer 【发布时间】:2019-05-13 11:33:02 【问题描述】:

我正在使用 slixmpp 连接到 XMPP 服务器,我需要在提供 HTTP 协议时访问此连接,我试图保持持久连接,而不是为每个 HTTP 请求连接到 XMPP 服务器。我正在使用 TCPServer 来获取 HTTP 的功能。我写了这段代码。

import logging

from slixmpp import ClientXMPP
from slixmpp.exceptions import IqError, IqTimeout
import socketserver

from time import sleep
class EchoBot(ClientXMPP):

        def __init__(self, jid, password):
            ClientXMPP.__init__(self, jid, password)

            self.add_event_handler("session_start", self.session_start)
            self.add_event_handler("message", self.message)

        def session_start(self, event):
            self.send_presence()
            self.get_roster()


        def message(self, msg):
            print(msg)
            if msg['type'] in ('chat', 'normal'):
                msg.reply("Thanks for sending\n%(body)s" % msg).send()
class MyTCPHandler(socketserver.BaseRequestHandler):
        xmpp = EchoBot('xxx@fcm.googleapis.com', 'xyz')
        def __init__(self,request, client_address,server):
            super().__init__(request, client_address,server)
            self.xmpp.connect(address=('fcm-xmpp.googleapis.com',5235),use_ssl=True,disable_starttls=True)
            self.xmpp.process(forever=True)

        def handle(self):
            self.data = self.request.recv(1024).strip()
            print(" wrote:".format(self.client_address[0]))
            print(self.data)
            # just send back the same data, but upper-cased
            self.request.sendall(self.data.upper())


if __name__ == '__main__':

        logging.basicConfig(level=logging.DEBUG,format='%(levelname)-8s %(message)s')
        HOST, PORT = "localhost", 9999
        server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
        server.serve_forever()

这是第一次。 MyTCPHandler 句柄函数只在第一次工作,第二次,它不返回任何响应。我正在使用telnet localhost 9999 来测试连接。这里可能出了什么问题?有没有更好的方法来实现我正在寻找的结果?

如果我评论这三行 TCPServer 按预期工作。

# xmpp = EchoBot('xxx@fcm.googleapis.com', 'xyz')
        def __init__(self,request, client_address,server):
            super().__init__(request, client_address,server)
          #  self.xmpp.connect(address=('fcm-xmpp.googleapis.com',5235),use_ssl=True,disable_starttls=True)
          #  self.xmpp.process(forever=True)

【问题讨论】:

【参考方案1】:

我使用 asyncio 解决了这个问题

import logging

from slixmpp import ClientXMPP
from slixmpp.exceptions import IqError, IqTimeout

import logging
logging.basicConfig(format='%(asctime)s %(message)s', level=logging.INFO)
log = logging.getLogger(__name__)

import asyncio
import base64
import slixmpp
from aiohttp import web

XMPP = None

class EchoBot(ClientXMPP):

    def __init__(self, jid, password):
        ClientXMPP.__init__(self, jid, password)
        self.connected_future = asyncio.Future()
        self.add_event_handler("session_start", self.session_start)
        self.add_event_handler("message", self.message)

    def session_start(self, event):
        self.send_presence()
        self.get_roster()
    def message(self, msg):
        if msg['type'] in ('chat', 'normal'):
            msg.reply("Thanks for sending\n%(body)s" % msg).send()
    def reset_future(self):
        "Reset the future in case of disconnection"
        self.connected_future = asyncio.Future()


async def handle(request):
    "Handle the HTTP request and block until the vcard is fetched"
    err_404 = web.Response(status=404, text='Not found')
    print(await request.json())



    try:
        XMPP.send_raw('<message id="gsgsfssdfds"> <gcm xmlns="google:mobile:data"> "notification": "title": "change","body": "body changed","sound":"default","to" : "efsfdsf","message_id":"flajlfdjlfdklajflda","priority":"high","delivery_receipt_requested":true</gcm></message>')
    except Exception as e:
        print(e)
        log.warning("cannot send message")
        return err_404


    return web.Response(text="yes")

async def init(loop, host: str, port: str, avatar_prefix: str):
    "Initialize the HTTP server"
    app = web.Application(loop=loop)
    app.router.add_route('POST', '/', handle)
    srv = await loop.create_server(app.make_handler(), host, port)
    log.info("Server started at http://%s:%s", host, port)
    return srv

def main(namespace):
    "Start the xmpp client and delegate the main loop to asyncio"
    loop = asyncio.get_event_loop()
    global XMPP
    XMPP = EchoBot('xxx@gcm.googleapis.com', 'ysfafdafdsfa')
    XMPP.connect(use_ssl=True,disable_starttls=False)
    #XMPP.connect()
    loop.run_until_complete(init(loop, namespace.host, namespace.port,
                                 namespace.avatar_prefix))
    XMPP.reset_future()
    loop.run_until_complete(XMPP.connected_future)


    try:
        loop.run_forever()
    except KeyboardInterrupt:
        import sys

def parse_args():
    "Parse the command-line arguments"
    from argparse import ArgumentParser
    parser = ArgumentParser()
    parser.add_argument('--jid', '-j', dest='jid', default=JID,
                        help='JID to use for fetching the vcards')
    parser.add_argument('--password', '-p', dest='password', default=PASSWORD,
                        help='Password linked to the JID')
    parser.add_argument('--host', dest='host', default=HOST,
                        help='Host on which the HTTP server will listen')
    parser.add_argument('--port', dest='port', default=PORT,
                        help='Port on which the HTTP server will listen')
    parser.add_argument('--avatar_prefix', dest='avatar_prefix',
                        default=AVATAR_PREFIX,
                        help='Prefix path for the avatar request')
    return parser.parse_args()

HOST = '127.0.0.1'
PORT = 8765
JID = 'changeme@example.com'
PASSWORD = 'changemetoo'
AVATAR_PREFIX = 'avatar/'

if __name__ == "__main__":
    print(parse_args())
    main(parse_args())

【讨论】:

以上是关于与 TCPServer 保持另一个持久的 TCP 连接的主要内容,如果未能解决你的问题,请参考以下文章

PHP:保持与 XMPP 聊天客户端的持久连接

Python网络编程9-实现TCP三次握手与四次挥手

用Ruby(TCPServer)创建的简单服务器,如何从另一个IP访问?

ESP-C3入门9. 创建TCP Server

ESP-C3入门9. 创建TCP Server

WIFI模块开发教程之W600网络篇2:AP模式下TCP Server通信