我正在使用 PHPssh2
库,并且只是在做:
$ssh = ssh2_connect($hostname, $port);
问题是我想设置一个超时,即 5 秒后停止尝试连接。据我所知,ssh2 库不支持本机连接超时。如何实现超时包装器?
我知道这是一个旧线程,但问题仍然存在。所以,这里是它的解决方案。
ssh2_connect()
使用socket_connect()
. socket_connect
依赖于default_socket_timeout
默认设置为 60 秒的 php ini 配置参数(http://php.net/manual/en/filesystem.configuration.php#ini.default-socket-timeout)
因此,解决我们问题的最简单方法是在运行时将 ini 设置更改为我们想要的值,然后再改回 ini 文件中设置的值,这样我们就可以避免影响软件的其他部分。在下面的示例中,新值设置为 2 秒。
$originalConnectionTimeout = ini_get('default_socket_timeout');
ini_set('default_socket_timeout', 2);
$connection = ssh2_connect('1.1.1.1');
ini_set('default_socket_timeout', $originalConnectionTimeout);
您可以通过阅读 libssh2 的源代码 ( https://github.com/libssh2/libssh2 )找到有关 ssh2 for php 工作原理的更多详细信息。
我一直在为同样的问题苦苦挣扎一段时间。事实上,只要目标服务器的最大连接时间限制,尝试使用 ssh2 连接到“死”或无响应的服务器将使您的应用程序停止。
预先检测您的实例是否会在插入实例时给您带来麻烦的简单方法是对其进行 ping 操作(查看它是否有响应)。
function getPing($addr)
{
//First try a direct ping
$exec = exec("ping -c 3 -s 64 -t 64 ".$addr);
$array = explode("/", end(explode("=", $exec )) );
if(isset($pingVal[1]))
{
//There was a succesful ping response.
$pingVal = ceil($array[1]);
}
else
{
//A ping could not be sent, maybe the server is blocking them, we'll try a generic request.
$pingVal = callTarget($addr);
}
echo intval($pingVal)."ms";
if($pingVal > ["threshold"])
{
return false;
}
return true;
}
function callTarget($target)
{
$before = microtime();
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target);
curl_setopt($ch, CURLOPT_NOBODY, true);
if (curl_exec($ch))
{
curl_close($ch);
return (microtime()-$before)*1000;
}
else
{
curl_close($ch);
return 9999;
}
}
这种方法可以让您更快地响应服务器的状态,因此您知道是否要浪费时间 ssh-ing 到它。
libssh2库本身不会执行 connect(),因此它不必为此提供超时。但是,libssh2 确实为其提供的功能提供超时...
如果远程端的防火墙阻止 ping 数据包,使用 ping 执行可能会导致问题。此外,这可能会导致不同环境出现问题,或者可能存在其他障碍,因为访问限制执行命令。
您可以将 ini_get、ini_set aprroach 用于“default_socket_timeout”,正如 Patkos Csaba 之前所说的那样。但从我的角度来看,最好使用指定超时的测试套接字连接:
function sock_online_test($ip, $timeout=0.1, $port='22') {
$fp = @fsockopen($ip, $port, $errno, $errstr, $timeout);
if (!$fp) {
return false;
} else {
fclose($fp);
return true;
}
}
$online = sock_online_test('192.168.1.1', 5);
// even domain may works
$online = sock_online_test('myserver.com', 5);