3

我正在使用PHP 套接字扩展(基本上是围绕socket(2)-related linux 系统调用的包装器),并且希望在为后续请求提供一个请求时重用我打开的套接字。性能是一个关键因素。

我打开的套接字都指向同一个 IP,这使得其他功能的使用pfsockopen()变得不可能(因为它每次都重用同一个套接字),我一次需要几个。

问题

如果我让我打开的套接字故意打开服务一个请求,(我不调用socket_close()or socket_shutdown())并将具有完全相同参数的套接字连接到为下一个请求提供服务的同一 IP;linux 会重新使用之前打开的套接字/文件描述符吗?

我最终要做的是避免每次请求都进行 TCP 握手。

附加信息

  • 我使用 apache worker MPM - 这意味着不同的请求可以但不一定来自不同的进程。为了简单起见,我们假设所有请求都来自同一个进程。

  • 我可以在 PHP 中获取打开和连接的套接字的文件描述符 ID。我可以打开和读写/dev/fd/{$id},但没有任何目的 - 它没有与远程服务器通信(也许这是一种天真的方法)。如果有人知道如何完成这项工作,我也会认为这也是一个可以接受的答案。

4

3 回答 3

5

如果您想在同一进程中重用套接字,只需保持连接打开即可。这实际上是避免 TCP 握手的唯一选择。确保keepalives开启:

s.setsockopt( socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)

如果您想生成新进程并将连接传递给它们,是的,它们将能够写入/dev/fd/{$id},这将通过网络发送数据。只需确保在 exec 期间未关闭套接字(了解SOCK_CLOEXEC)。

将套接字传递给不相关的进程是不可能的。您必须使用某种形式的进程间通信来实现这一点,而且我不确定内部网或 Internet 条件下 TCP 握手的开销是否足以证明与此相关的复杂性和其他开销是合理的。

于 2012-06-19T21:05:14.440 回答
0

如果我让我打开的套接字故意打开服务一个请求,(我不调用 socket_close() 或 socket_shutdown())并将具有完全相同参数的套接字连接到为下一个请求提供服务的同一 IP;linux 会重新使用之前打开的套接字/文件描述符吗?

不,但是如果您处于相同的过程中,您可以始终继续使用原始版本。您所说的实际上是连接池。

于 2012-06-19T21:43:52.940 回答
0

虽然Jirka Hanika给出的答案对于大多数系统都是正确的,但我得出的结论是遗憾地不适用于 PHP;使用 PHP套接字扩展重新使用套接字是不可能从用户空间实现的。

导致这个结论的代码是:

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_KEEPALIVEset 的套接字,向其写入请求并读取响应。然后它会选择性地关闭套接字(切换行注释)并回显当前进程的 PID(以确保您在同一个进程中)。

您将看到,无论您是否关闭套接字,为上一个请求创建的文件描述符在此循环执行开始时将不再存在,并且将创建并连接一个全新的套接字。

我无法测试SOCK_CLOEXEC,因为它(还没有?)在扩展中实现。

(这是使用 PHP 5.4.0 测试的)

于 2012-06-20T18:44:31.260 回答