Django:与 TCP 服务器通信(扭曲?)
Django: communicate with TCP server (with twisted?)
我有一个 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 连接。所以我现在的问题是,是否可以优化设置(我确信可以)以及如何完成。
据我了解,现在的问题是如何将 Twisted 集成到 Django 应用程序中。这似乎不是一个好主意,因为 Twisted 的事件循环会阻塞进程。
您可以尝试 运行 在非阻塞环境中使用 gunicorn Django 并使用 gevent 来实现所需的所有通信。
如果那不可能 - 有一个 answer suggesting standalone Django app 作为在 Django 中使用 Twisted 的方法(或者更确切地说是 Twisted 中的 Django 位)。
就我个人而言,我会选择 gevent。使用 Twisted 大约 2 年之后,它看起来功能强大但又老旧、笨重、难学且难调试。
除非你猴子修补 Django(如@pss 所述),否则这是行不通的
我有类似的情况所以这就是我所做的。
- 运行 一个独立的扭曲恶魔。
- 要从 Django 到 Twisted 进行通信,请使用 Unix 套接字。本地 twisted 服务器可以侦听 Unix 套接字 (AF_UNIX),Django 可以简单地连接到该套接字。这将避免通过 TCP 堆栈
- 要从 Twisted 到 Django 进行通信,您有多种选择,
a) 用数据调用 Django url
b) 启动脚本(Django 管理命令)
c) 使用 celery 启动上面的 Django 命令
d) 使用队列(zeromq 或 rabbit)并让 Django 管理命令监听队列(首选)
使用最后一个选项,您可以获得更好的吞吐量、耐用性,并且可以很好地扩展。
您可能需要考虑在您的 Django 应用程序中使用 Twisted 。 Here's an excellent talk about that, and a simple example of deploying Django on Twisted, and a deployment tool for Django that uses Twisted.
我有一个 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 连接。所以我现在的问题是,是否可以优化设置(我确信可以)以及如何完成。
据我了解,现在的问题是如何将 Twisted 集成到 Django 应用程序中。这似乎不是一个好主意,因为 Twisted 的事件循环会阻塞进程。
您可以尝试 运行 在非阻塞环境中使用 gunicorn Django 并使用 gevent 来实现所需的所有通信。 如果那不可能 - 有一个 answer suggesting standalone Django app 作为在 Django 中使用 Twisted 的方法(或者更确切地说是 Twisted 中的 Django 位)。
就我个人而言,我会选择 gevent。使用 Twisted 大约 2 年之后,它看起来功能强大但又老旧、笨重、难学且难调试。
除非你猴子修补 Django(如@pss 所述),否则这是行不通的 我有类似的情况所以这就是我所做的。
- 运行 一个独立的扭曲恶魔。
- 要从 Django 到 Twisted 进行通信,请使用 Unix 套接字。本地 twisted 服务器可以侦听 Unix 套接字 (AF_UNIX),Django 可以简单地连接到该套接字。这将避免通过 TCP 堆栈
- 要从 Twisted 到 Django 进行通信,您有多种选择, a) 用数据调用 Django url b) 启动脚本(Django 管理命令) c) 使用 celery 启动上面的 Django 命令 d) 使用队列(zeromq 或 rabbit)并让 Django 管理命令监听队列(首选)
使用最后一个选项,您可以获得更好的吞吐量、耐用性,并且可以很好地扩展。
您可能需要考虑在您的 Django 应用程序中使用 Twisted 。 Here's an excellent talk about that, and a simple example of deploying Django on Twisted, and a deployment tool for Django that uses Twisted.