Django:与 TCP 服务器通信(使用扭曲?)

Posted

技术标签:

【中文标题】Django:与 TCP 服务器通信(使用扭曲?)【英文标题】:Django: communicate with TCP server (with twisted?) 【发布时间】:2015-03-11 10:48:47 【问题描述】:

我有一个 django 应用程序,它需要与远程 TCP 服务器通信。该服务器将发送包,根据包是什么,我需要将条目添加到数据库并通知应用程序的其他部分。我还需要主动向 TCP 服务器发送请求,例如当用户导航到某个页面时,我想订阅 TCP 服务器上的某个流。所以双向沟通都需要进行。

到目前为止,我使用以下解决方案:

我写了一个自定义的 Django 命令,我可以从它开始

python manage.py listen

此命令将使用reactor.connectTCP(IP, PORT, factory) 启动一个扭曲的套接字服务器,并且由于它是一个 django 命令,我将可以访问数据库和我的应用程序的所有其他部分。

但是由于我还希望能够通过某个 django 视图触发向 TCP 服务器发送一些东西,所以我有一个额外的套接字服务器,它在我的扭曲应用程序中由 reactor.listenTCP(PORT, server_factory) 启动。

然后,我将在我的 django 应用程序中直接连接到这个服务器,在一个新线程中:

class MSocket:

    def __init__(self):
        self.stopped = False
        self.socket = None
        self.queue = []
        self.process = start_new_thread(self.__connect__, ())
        atexit.register(self.terminate)


    def terminate(self):
        self.stopped = True
        try:
            self.socket.close()
        except:
            pass

    def __connect__(self):
        if self.stopped:
            return
        attempts = 0
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        while True and not self.stopped:
            try:
                print "Connecting to Socket Server..."
                self.socket.connect(("127.0.0.1", settings.SOCKET_PORT))
                print "Connection Successful!"
                for msg in self.queue:
                    self.socket.send(msg)
                self.queue = []
                break
            except:
                pause = min(int(round(1.2**attempts)), 30)
                print "Connection Failed! Try again in " + str(pause) + " seconds."
                sleep(pause)
                attempts += 1

        self.__loop__()

    def __loop__(self):
        if self.stopped:
            return
        while True and not self.stopped:
            try:
                data = self.socket.recv(1024)
            except:
                try:
                    self.socket.close()
                except:
                    pass
                break
            if not data:
                break
        self.__connect__()

    def send(self, msg):
        try:
            self.socket.send(msg)
            return True
        except:
            self.queue.append(msg)
            return False


m_socket = MSocket()

m_socket 然后将由主urls.py 导入,以便它以 django 开头。

所以我的设置看起来像这样:

发送到 TCP 服务器:

Django (connect:8001) ------->  (listen:8001) Twisted (connect:4444) ------> (listen:4444) TCP-Server

从 TCP 服务器接收

TCP-Server (listen:4444) ------> (connect:4444) Twisted ---(direct access)---> Django

这一切似乎都是这样工作的,但我担心这不是一个很好的解决方案,因为我必须打开这个额外的 TCP 连接。所以我现在的问题是,是否可以优化设置(我确信可以)以及如何完成。

【问题讨论】:

【参考方案1】:

除非你对 Django 进行猴子补丁(如 @pss 所述),否则这不会起作用 我有类似的情况,所以我就是这样做的。

    运行一个单独的扭曲守护进程。 要从 Django 与 Twisted 通信,请使用 Unix 套接字。本地扭曲服务器可以监听 Unix 套接字(AF_UNIX),Django 可以简单地连接到该套接字。这将避免通过 TCP 堆栈 要从 Twisted 与 Django 通信,您有多种选择, a) 使用数据调用 Django url b) 启动脚本(Django 管理命令) c) 使用 celery 启动上述 Django 命令 d) 使用队列(zeromq 或 rabbit)并让您的 Django 管理命令监听队列(首选)

使用最后一个选项,您可以获得更好的吞吐量、持久性并且可以很好地扩展。

【讨论】:

听起来很有趣。我一定会检查这个设置。难道也可以使用 Unix 套接字从 Twisted 到 Django 进行通信吗?或者出于某种原因这是一个坏主意? 您需要在套接字的另一端有一个侦听器,这意味着您需要以某种方式在 Django 中旋转一个线程来侦听该套接字,因为它需要是非阻塞的。 (您可以运行另一个 Django 命令来监听,但使用数据调用 Django URL 更容易)。【参考方案2】:

您可能需要考虑在您的 Django 应用程序中使用 Twisted。 Here's an excellent talk about that、a simple example of deploying Django on Twisted、deployment tool for Django that uses Twisted。

【讨论】:

【参考方案3】:

据我所知,问题在于如何将 Twisted 集成到 Django 应用程序中。这似乎不是一个好主意,因为 Twisted 的事件循环阻塞了这个过程。

您可以尝试使用gunicorn 在非阻塞环境中运行 Django,并使用 gevent 实现所需的所有通信。 如果这是不可能的 - 有一个 answer 建议 standalone Django app 作为在 Django 中使用 Twisted(或者更确切地说是 Twisted 中的 Django 位)的一种方式。

我个人会选择 gevent。使用 Twisted 大约 2 年之后,它似乎是一个强大但老旧、笨重、难以学习和难以调试的工具。

【讨论】:

谢谢,但不幸的是我无法控制我正在连接的 TCP 服务器。 我认为,设计应该由服务器驱动,因此您要么必须实现将在单个连接上双向工作的服务器协议,要么在服务器无法提供服务时使用两个连接一。 也许我不够具体。问题不在于服务器或协议无法处理双向通信。问题是如何在 Django 中集成这种通信。由于扭曲的服务器在不同的进程中运行,并且与 Django 相比,它是非阻塞的,因此很难从 Django 视图内部发送消息。 我改变了答案。也许这会更有帮助。

以上是关于Django:与 TCP 服务器通信(使用扭曲?)的主要内容,如果未能解决你的问题,请参考以下文章

django使用websocket

带有 python 扭曲服务器的 Qt C++ tcp 客户端

DHT TCP API 在内部使用 UDP 服务请求(扭曲)

检测 TCP 何时拥塞 python 扭曲套接字服务器

Python 将 http post body 扭曲转发到 tcp 端口

如何检测和删除扭曲的死TCP连接?