PHP Conference Japan 2024

socket_connect

(PHP 4 >= 4.1.0, PHP 5, PHP 7, PHP 8)

socket_connect启动套接字连接

描述

socket_connect(Socket $socket, string $address, ?int $port = null): bool

使用 Socket 实例 socket 启动到 address 的连接,该实例必须是使用 socket_create() 创建的 Socket 实例。

参数

socket

使用 socket_create() 创建的 Socket 实例。

address

如果 socketAF_INET,则 address 参数为点分十进制表示法的 IPv4 地址(例如 127.0.0.1);如果启用了 IPv6 支持且 socketAF_INET6,则为有效的 IPv6 地址(例如 ::1);或者如果套接字族为 AF_UNIX,则为 Unix 域套接字的文件路径。

port

仅当连接到 AF_INETAF_INET6 套接字时,才会使用 port 参数,并且它是必需的,它指定了应建立连接的远程主机上的端口。

返回值

成功时返回 true,失败时返回 false。可以使用 socket_last_error() 获取错误代码。此代码可以传递给 socket_strerror() 以获取错误的文本解释。

注意:

如果套接字是非阻塞的,则此函数将返回 false 并显示错误 Operation now in progress

变更日志

版本 描述
8.0.0 socket 现在是 Socket 实例;以前,它是一个 resource
8.0.0 port 现在可以为空。

参见

添加注释

用户贡献的注释 11 个注释

w at ff dot st
21 年前
connect 的手册页
EINPROGRESS
套接字是非阻塞的,并且连接无法立即完成。可以通过选择套接字进行写入来选择(2)或轮询(2)以完成。在 select 指示可写性后,使用 getsockopt(2) 读取 SOL_SOCKET 级别上的 SO_ERROR 选项以确定 connect 是否成功完成(SO_ERROR 为零)或不成功(SO_ERROR 是此处列出的常用错误代码之一,解释了失败的原因)。

使用 socket_getoption($socket,SOL_SOCKET,SO_ERROR)。如果得到值 115,则表示正在连接。如果得到的值不同于 115 和 0,则表示发生了错误(使用 socket_strerror() 查看是什么错误)。

但是,我不知道这在 Windows 下是如何工作的,也许根本无法工作。它应该在 Linux 下工作(手册页上说)。
tacapi at canela dot com
7 年前
提醒大家:确保您传递给 ping 和套接字函数的 IP 格式正确。

例如:192.168.0.18 -> OK
192.168.0.018 -> 将导致“未知主机”

我遇到了 11004 错误,直到我意识到这是问题所在才解决。

(这可能对某些人有用:检查传递给 ping 和套接字函数的参数 IP 是否为正确格式的 IP 地址)
greg at mtechsolutions dot ca
21 年前
如果您使用的是非阻塞模式,请确保在连接后才启用它,否则您将收到消息

PHP Warning: socket_connect() unable to connect [115]: Operation now in progress in file.php on line 123

并且 socket_connect() 将返回 false(即使它会连接)。
jerrywilborn at gmail dot com
15 年前
这将打印来自真正的“telnet”服务器(路由器、交换机、主机等)的横幅。

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($socket, '127.0.0.1', 23);

while (TRUE) {
$r = array($socket);
$c = socket_select($r, $w = NULL, $e = NULL, 5);

foreach ($r as $read_socket) {
if ($r = negotiate($read_socket)) {
var_dump($r);
exit;
}
}
}

function negotiate ($socket) {
socket_recv($socket, $buffer, 1024, 0);

for ($chr = 0; $chr < strlen($buffer); $chr++) {
if ($buffer[$chr] == chr(255)) {

$send = (isset($send) ? $send . $buffer[$chr] : $buffer[$chr]);

$chr++;
if (in_array($buffer[$chr], array(chr(251), chr(252)))) $send .= chr(254);
if (in_array($buffer[$chr], array(chr(253), chr(254)))) $send .= chr(252);

$chr++;
$send .= $buffer[$chr];
} else {
break;
}
}

if (isset($send)) socket_send($socket, $send, strlen($send), 0);
if ($chr - 1 < strlen($buffer)) return substr($buffer, $chr);

}
Cedar Myers
13 年前
似乎可以通过在调用 socket_connect() 之前设置 SO_SNDTIMEO 选项来指定超时值

<?php
socket_set_option
($socket, SOL_SOCKET, SO_SNDTIMEO, array('sec' => $seconds, 'usec' => $milliseconds));
socket_connect($socket, $address, $port)//...
?>
maganap
16 年前
您好!

对于 TCP 连接:socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
如果您在 socket_connect() 中遇到问题,并且 socket_strerror() = “Permission denied”,则可能是 SELinux 配置问题。

检查 SELinux 是否已启用
# /usr/sbin/sestatus -v
如果已启用,您可以键入以下命令
# setsebool httpd_can_network_connect=1

就是这样... 我读到您需要重新启动,但我没有重新启动,它也能正常工作。更多信息,您可以查看
http://arkiv.netbsd.se/?ml=squirrelmail-users&a=2005-11&t=1523021
vshih at yahoo
15 年前
rbarnes 的提示很有用,但我发现我需要在 while 循环中添加对 SOCKET_EISCONN 的检查

...
$error = socket_last_error();

if ($error == SOCKET_EISCONN) {
$connected = true;
break;
}
...

至少在 Mac OS X 10.5 上。
rbarnes at fake dot com
16 年前
这是一个非阻塞连接的示例,它的执行速度应该比 Seymour 在下面发布的示例快得多。

<?php
function msConnectSocket($remote, $port, $timeout = 30) {
# 无论 $remote 是主机名还是 IP,此方法都有效
$ip = "";
if( !
preg_match('/^\d+\.\d+\.\d+\.\d+$/', $remote) ) {
$ip = gethostbyname($remote);
if (
$ip == $remote) {
$this->errstr = "套接字连接错误:未知主机";
return
NULL;
}
} else
$ip = $remote;

if (!(
$this->_SOCK = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP))) {
$this->errstr = "套接字创建错误:".socket_strerror(socket_last_error());
return
NULL;
}

socket_set_nonblock($this->_SOCK);

$error = NULL;
$attempts = 0;
$timeout *= 1000; // 调整,因为我们以 1 毫秒的增量休眠
$connected;
while (!(
$connected = @socket_connect($this->_SOCK, $remote, $port+0)) && $attempts++ < $timeout) {
$error = socket_last_error();
if (
$error != SOCKET_EINPROGRESS && $error != SOCKET_EALREADY) {
$this->errstr = "套接字连接错误:".socket_strerror($error);
socket_close($this->_SOCK);
return
NULL;
}
usleep(1000);
}

if (!
$connected) {
$this->errstr = "套接字连接错误:连接超时,超时时间为 $timeout 秒。".socket_strerror(socket_last_error());
socket_close($this->_SOCK);
return
NULL;
}

socket_set_block($this->_SOCK);

return
1;
}
?>
peter at videoripper dot org
15 年前
这将为您提供一个简单的端口检查器。

请注意,在生产机器上,您可能需要更改错误报告级别,
因为不成功的连接将在日志中产生“无法建立连接,因为
目标机器主动拒绝了它”的错误。

在 Windows 下,请确保在您的 php.ini 中启用了 php_sockets.dll 扩展。

<?php
$address
=$_SERVER['REMOTE_ADDR'];

if (isset(
$_REQUEST['port']) and
(!
strlen($_REQUEST['port'])==0))
$port=$_REQUEST['port'];
else
unset(
$port);

if (isset(
$port) and
(
$socket=socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) and
(
socket_connect($socket, $address, $port)))
{
$text="IP $address,端口 $port 连接成功";
socket_close($socket);
}
else
$text="无法连接<pre>".socket_strerror(socket_last_error())."</pre>";

echo
"<html><head></head><body>".
$text.
"</body></html>";
?>

问候,

Peter。
thewanderer
13 年前
请注意,从 PHP 5.3 开始,无法将 IPv6 多播发送到链路本地地址,因为 socket_connect() 只是 connect() 的一个精简版本,不支持传递 sin6_scope_id - 例如,发送数据包到 ff02::1(所有节点)时需要范围 ID。
起初我以为需要使用 SO_BINDTODEVICE 选项(PHP 中未定义的常量 - 使用数字值 25)将套接字绑定到设备,但这没有区别,只要求 root 权限才能产生无用的结果。
此外,如果您认为只是因为 socket_sendto() 返回了一个正数的字节数就发送了多播数据包到链路本地地址,那么您可能错了 - 仅仅返回成功并不意味着数据包通过任何链路发送。在我的测试用例中,我发送到 ff02::1,我没有检测到任何错误,但是 Wireshark 没有显示任何数据包。它们最终进入虚无。
这与本地接收套接字的处理无关,因此 UDP 侦听器在 IPv6/UDP 中应该仍然照常工作。不过,您可能需要求助于 C 来实现多播器。
seymour@itsyourdomain
21 年前
以下是如何使用套接字函数实现超时。

此示例适用于阻塞套接字,但只需稍作修改即可用于阻塞和非阻塞套接字。在非阻塞模式下,第一次调用 connect 将返回 115 EINPROGRESS,如果连接尚未失败或成功,则后续调用将返回 114 EALREADY。连接成功后,将返回套接字资源。

<?
$host = "127.0.0.1";
$port = "80";
$timeout = 15; //超时时间(秒)

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)
or die("无法创建套接字\n");

socket_set_nonblock($socket)
or die("无法在套接字上设置非阻塞\n");

$time = time();
while (!@socket_connect($socket, $host, $port))
{
$err = socket_last_error($socket);
if ($err == 115 || $err == 114)
{
if ((time() - $time) >= $timeout)
{
socket_close($socket);
die("连接超时。\n");
}
sleep(1);
continue;
}
die(socket_strerror($err) . "\n");
}

socket_set_block($this->socket)
or die("无法在套接字上设置阻塞\n");
?>
To Top