我正在使用PHP sockets extension(基本上是围绕socket(2)
相关的linux系统调用的包装器),并希望重新使用我在后续服务中提供一个请求时打开的套接字。绩效是一个关键因素。
我打开的套接字都是相同的IP,这使得像pfsockopen()
这样的其他功能的使用变得不可能(因为它每次都重复使用相同的单个套接字),我一次只需要几个。
问题
如果我离开套接字,我打开服务一个请求故意打开,(我不打电话给socket_close()
或socket_shutdown()
)并将具有完全相同参数的套接字连接到下一个服务的同一IP请求; linux会重新使用先前打开的socket / file-descriptor吗?
我最终想做的是避免每次请求都有TCP握手。
其他信息:
我使用apache worker MPM - 这意味着不同的请求可以,但不一定是来自不同的进程。为简单起见,我们假设所有请求都来自同一个进程。
我可以在PHP中获取打开并连接的套接字的文件描述符ID。我可以打开并读取和写入/dev/fd/{$id}
,但没有任何意义 - 它不与远程服务器通信(这可能是一种天真的方法)。如果有人知道如何完成这项工作,我认为这也是一个可以接受的答案。
答案 0 :(得分:5)
如果要在同一进程中重用套接字,只需将连接保持打开即可。这实际上是避免TCP握手的唯一选择。确保Keepalive已开启:
s.setsockopt( socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
如果您想生成新进程并将连接传递给它们,是的,它们将能够写入/dev/fd/{$id}
,这将通过网络发送数据。只需确保在exec期间套接字没有关闭(了解SOCK_CLOEXEC
)。
无法将套接字传递给不相关的进程。您将不得不使用某种形式的进程间通信来实现这一点,而且我不确定在Intranet或Internet条件下TCP握手的开销是否足以证明与此相关的复杂性和其他开销。
答案 1 :(得分:0)
如果我离开插座,我打开服务一个请求故意打开, (我不调用socket_close()或socket_shutdown())并连接一个 套接字具有与下一个服务相同IP的完全相同的参数 请求;将linux重新使用以前打开的套接字/ 文件描述符?
不,但如果你在同一个过程中,你可以随时继续使用原始的。你在谈论的是真正的连接池。
答案 2 :(得分:0)
虽然Jirka Hanika给出的答案对大多数系统都是正确的,但我得出的结论是遗憾的是它不适用于PHP;使用PHP sockets extension重新使用套接字是不可能从用户空间实现的。
导致这一结论的代码是:
function statDescriptors() {
foreach (glob('/proc/self/fd/*') as $sFile) {
$r = realpath($sFile);
// ignore local file descriptors
if($r === false) {
echo `stat {$sFile}`, "\n";
}
}
}
header('Content-Type: text/plain');
statDescriptors();
$oSocket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($oSocket, SOL_SOCKET, SO_KEEPALIVE, 1);
socket_set_option($oSocket, SOL_SOCKET, SO_REUSEADDR, 1);
socket_connect($oSocket, '173.194.35.33', 80); // Google IP
socket_write($oSocket, 'GET / HTTP/1.0' . "\r\n");
socket_write($oSocket, 'Connection: Keep-Alive' . "\r\n\r\n");
socket_read($oSocket, 1024 * 8);
// socket_close($oSocket); // toggle this line comment during test
echo 'PID is: ', getmypid(), "\n";
statDescriptors();
此代码将stat()
当前进程'在其执行的开始和结束时打开套接字文件描述符。在它之间它会打开一个SO_KEEPALIVE
设置的套接字,向它写一个请求并读取一个响应。然后它会选择关闭套接字(切换行注释)并回显当前进程的PID(以确保你处于同一个进程中)。
您将看到,无论您是否关闭套接字,在此周期执行开始时将不再存在为前一个请求创建的文件描述符,并且将创建并连接一个全新的套接字。
我无法测试SOCK_CLOEXEC
,因为它不是(还是?)在扩展程序中实现。
(这是使用PHP 5.4.0测试的)