对不起这个标题,但很难用几句话来解释。
我写了一个小的web代理 - 不是apache或任何类型的常见网络服务器 - 谁的角色是执行一些PHP代码。
有两种方法可以做到:
1)fork一个新的php -f file.php
2)从网络代理中调用http://localhost/file.php。
我认为会有很多并发请求到该代理,每个请求将保持活动至少20-30秒。
我的问题是:在分叉和通过http请求之间哪个更好?
感谢任何提示!
的Dario
答案 0 :(得分:0)
我最近也做了代理。并且 - 有第三种选择。甚至不需要调用自己或其他脚本,它是完全独立的,跨平台的......
所以 - 首先是我使用套接字完成了这个。我猜你也是这样做的,但是如果你不这样做的话,就把它写在这里。我将浏览器中的代理设置为特定端口,允许通过防火墙进入侦听PHP脚本。为了让它开始收听,我必须在端口80上“运行”脚本,所以我也得到了一个很好的实时控制台。
所以 - 脚本侦听套接字,并将其设置为NON-BLOCKING。它适用于循环(无限,需要时使用break断开) - * @ socket_accept()*用于查看是否有任何新连接,检查是否!== false。
最后,循环遍历(:D)所有生成的子套接字,它们存储在一个数组中。它是一个HTTP代理,因此所有这些都有一些特定的阶段(客户端发送标头,尝试访问远程服务器,发送客户端标头,从远程服务器接收数据)。通常会阻止(在使用 fsockopen()打开的远程套接字上读取的内容,并且没有办法将其设置为非阻塞这些,正在“模拟”非阻塞模式非常极端的时间 - 比如5微秒,最大chars read是128。
TL;博士;基本上这就像处理器多线程一样。
的无论其强> 的 !!!你需要套接字,如果这样做的话。
编辑:添加从所有自定义操作中剥离的示例代码:(是的,它很长)
set_time_limit(0); // so we don't get a timeout from PHP
// - can lead to sockets left open...
$config_port = 85; // port
$config_address = "192.168.0.199"; // IP address, most likely local with router
// if there's not a router between server and wan, use the wan IP
$config_to = 30; // global timeout in seconds
$config_connect_to = 2; // timeout for connecting to remote server
$config_client_to = 0.1; // timeout for reading client data
$config_remote_to = 10; // timeout for reading remote data (microseconds)
$config_remote_stage_to = 15; // timeout for last stage (seconds)
$config_backlog = 5000; // max backlogs, the more the better (usually)
$parent_sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); // parent socket
$tmp_res = @socket_bind($parent_sock, $config_address, $config_port);
if ($tmp_res === false){
echo "Can't bind socket.";
exit;
// address or port in use, for example by Apache
}
$tmp_res = @socket_listen($parent_sock, $config_backlog);
if ($tmp_res === false){
echo "Can't start socket listener.";
exit;
// hard to tell what can cause this
}
socket_set_nonblock($parent_sock); // non-blocking mode
$sockets = array(); // children sockets
$la = time(); // last activity
while (time() - $la < $config_to){
$spawn = @socket_accept($parent_sock); // check for new connection
if ($spawn !== false){
$la = time();
$ni = count($sockets);
$sockets[$ni] = array();
$sockets[$ni]["handle"] = $spawn;
$sockets[$ni]["stage"] = 1;
$sockets[$ni]["la"] = time(); // for some stages
$sockets[$ni]["client_data"] = "";
$sockets[$ni]["headers"] = array();
$sockets[$ni]["remote"] = false;
}
foreach ($sockets as &$sock){ // &$sock because we're gonna edit the var
switch ($sock["stage"]){
case 1: // receive client data
$read_data = @socket_read($sock["handle"], 2048);
if ($read_data !== false && $read_data !== ""){
$la = time();
$sock["la"] = microtime(true);
$sock["client_data"] .= $read_data;
} else if (microtime(true) - $sock["la"] > $config_client_to) {
// client data received (or too slow :D)
$sock["stage"] = 2; // go on
}
break;
case 2: // connect to remote
$headers = explode("\r\n", $sock["client_data"]);
foreach ($headers as $hdr){
$h_pos = strpos($hdr, ":");
if ($h_pos !== false){
$nhid = count($sock["headers"]);
$sock["headers"][strtolower(substr($hdr, 0, $h_pos))] = ltrim(substr($hdr, $h_pos + 1));
}
}
// we'll have to use the "Host" header to know target server
$sock["remote"] = @fsockopen($sock["headers"]["host"], 80, $sock["errno"], $sock["errstr"], $config_connect_to);
if ($sock["remote"] === false){
// error, echo it and close client socket, set stage to 0
echo "Socket error: #".$sock["errno"].": ".$sock["errstr"]."<br />\n";
flush(); // immediately show the error
@socket_close($sock["handle"]);
$sock["handle"] = 0;
} else {
$la = time();
// okay - connected
$sock["stage"] = 3;
}
break;
case 3: // send client data
$tmp_res = @fwrite($sock["remote"], $sock["client_data"]);
// this currently supports just client data up to 8192 bytes long
if ($tmp_res === false){
// error
echo "Couldn't send client data to remote server!<br />\n";
flush();
@socket_close($sock["handle"]);
@fclose($sock["remote"]);
$sock["stage"] = 0;
} else {
// client data sent
$la = time();
stream_set_timeout($sock["remote"], $config_remote_to);
$sock["la"] = time(); // we'll need this in stage 4
$sock["stage"] = 4;
}
break;
case 4:
$remote_read = @fread($sock["remote"], 128);
if ($remote_read !== false && $remote_read !== ""){
$la = time();
$sock["la"] = time();
@socket_write($sock["handle"], $remote_read);
} else {
if (time() - $sock["la"] >= $config_remote_stage_to){
echo "Timeout.<br />\n";
flush();
@socket_close($sock["handle"]);
@fclose($sock["remote"]);
$sock["stage"] = 0;
}
}
break;
}
}
}
foreach($sockets as $sock){
@socket_close($sock["handle"]);
@fclose($sock["remote"]);
}
@socket_close($parent_sock);