使用 PHP 或 Django 在 Apache 中重定向八位字节流
Posted
技术标签:
【中文标题】使用 PHP 或 Django 在 Apache 中重定向八位字节流【英文标题】:Redirect an octet stream in Apache using PHP or Django 【发布时间】:2015-08-08 12:30:45 【问题描述】:我有一个网络服务器,它通过端口 20000 上的八位字节流为客户端提供服务(它实际上是一个使用 node.js 托管的 socket.io 服务器)。这是在共享主机帐户上运行的,常规 Apache 服务器在端口 80 上运行(无法关闭,因此 socket.io 服务器在端口 20000 上)。由于防火墙等原因,我不能指望用户能够连接到端口 20000(或 80 以外的任何端口)。 那么,如何使用 Apache 服务器的 socket.io 服务器生成的八位字节流为客户端提供服务(有点像反向代理)? 不幸的是,由于限制,我不能在我的 Apache 服务器上使用 mod_proxy我的托管计划。我在想我可以用一个以某种方式打开套接字的 php 页面来做到这一点。
更新:我还在我的服务器上安装了 Django for Python 3,这可能很有用。请注意,代理不能简单地请求目标页面并将其返回给客户端,因为数据必须实时传输。
【问题讨论】:
Django 不能单独运行,它仍然需要一个网络服务器(Apache?) apache 的问题是如果页面“加载”时间过长,它会断开连接。如果您的防火墙阻止与除已运行服务(apache/ssh/...)之外的所有端口的连接,我认为您不走运。如果其他端口打开,您可以编写一个接收请求的服务,连接到流服务器,并提供数据 【参考方案1】:关于“它不能简单地返回目标页面”......这不是真的,因为这就是 HTTP 代理的全部内容。大多数协议代理使用套接字(相对于文件或管道)并且简单地将数据从套接字复制到套接字。 HTTP 代理做同样的事情,除了每个 HTTP 请求都需要握手,因此代理在到达有效负载之前需要来回发送一些数据包。您可以在 django 中非常轻松地创建 HTTP GET 代理。 POST 代理需要额外的操作。
我对 Socket.IO 不熟悉,但在研究...how does socket.io work?...看来它只使用“旧”HTTP 功能并将一切作为 REST 运行。 REST 被封装为持久套接字内的传输。
如果您在 Django 中寻找 TCP 或 IP 级别的代理,它不会发生。你的 apache 服务器,然后是 WSGI/CGI/whatever 关闭你的 TCP 套接字。您能够访问它的唯一方法是对服务器的这些部分拥有足够的权限。
这就是我要做的...在 django 中创建一个捕获 socket.io api 的 url 模式,并让它连接到执行以下操作的视图(未经测试的伪代码):
import urllib2, mimetypes
from django.http import HttpResponse
def ForwardToSocketIO(request):
# Capture the URL pattern
path = request.get_full_path()
# Create a URL opener
response = urllib2.urlopen('http://localhost:20000%s' % path)
# Capture and return response
django_response = HttpResponse(response.read())
django_response['Content-Type'] = 'octet-stream'
return django_response
希望这会有所帮助。我没有可用的八位字节流,因此很抱歉没有进行测试。
【讨论】:
【参考方案2】:似乎有可能并非不可能。我以前没有做过,但知道该怎么做,但我不知道防火墙对端口打开和关闭的影响。做事的基本理念是:
让您从端口 80 请求执行操作,并为响应该请求使用不同的端口与客户端通信。它将成为一条从一个端口接收请求并从另一个端口获得回复的隧道。一旦目的得到解决,只有一件事需要妥善处理,即尽快终止连接,除非它会在服务器上造成内存负载。
通过以下示例,您可以执行上述操作,但建议您在经过适当测试后谨慎使用。
参考:Programming with Sockets through PHP
这个例子展示了一个简单的对讲服务器。更改地址和端口变量以适合您的设置和执行。然后,您可以使用类似于以下命令的命令连接到服务器:telnet 192.168.1.53 10000(地址和端口与您的设置相匹配)。您键入的任何内容都将在服务器端输出,并回显给您。要断开连接,请输入“退出”。
<?php
error_reporting(E_ALL);
echo "<h2>TCP/IP Connection</h2>\n";
/* Get the port for the WWW service. */
$service_port = getservbyname('www', 'tcp');
/* Get the IP address for the target host. */
$address = gethostbyname('www.example.com');
/* Create a TCP/IP socket. */
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false)
echo "socket_create() failed: reason: " .
socket_strerror(socket_last_error()) . "\n";
else
echo "OK.\n";
echo "Attempting to connect to '$address' on port '$service_port'...";
$result = socket_connect($socket, $address, $service_port);
if ($result === false)
echo "socket_connect() failed.\nReason: ($result) " .
socket_strerror(socket_last_error($socket)) . "\n";
else
echo "OK.\n";
$in = "HEAD / HTTP/1.1\r\n";
$in .= "Host: www.example.com\r\n";
$in .= "Connection: Close\r\n\r\n";
$out = '';
echo "Sending HTTP HEAD request...";
socket_write($socket, $in, strlen($in));
echo "OK.\n";
echo "Reading response:\n\n";
while ($out = socket_read($socket, 2048))
echo $out;
echo "Closing socket...";
socket_close($socket);
echo "OK.\n\n";
?>
【讨论】:
能够像@Ramast 所说的那样路由连接对我来说毫无用处,因为我可以假设客户端可以访问的唯一端口是 Web 端口 (80),它已经被阿帕奇服务器。因此,我需要一种通过 Apache 服务器为客户端提供服务的方法。也许 WSGI 会派上用场?以上是关于使用 PHP 或 Django 在 Apache 中重定向八位字节流的主要内容,如果未能解决你的问题,请参考以下文章
VMware+CentOS+Apache+php+python+Django+gunicorn配置
为啥建议使用不同的服务来托管 django 的静态文件(如 nginx 或 apache)?
错误:在 apache 上运行 django 时找不到目标 WSGI 脚本或无法统计