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(必须是使用 socket_create() 创建的 Socket 实例)启动到 address 的连接。

参数

socket

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

address

address 参数可以是点分十进制表示法中的 IPv4 地址(例如 127.0.0.1)(如果 socketAF_INET)、有效的 IPv6 地址(例如 ::1)(如果启用了 IPv6 支持并且 socketAF_INET6)或 Unix 域套接字的文件路径名(如果套接字族是 AF_UNIX)。

port

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

返回值

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

注意:

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

变更日志

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

参见

添加笔记

用户贡献笔记 14 笔记

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

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

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

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

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

(可能对某些人有用:检查传递给您的 ping 和 socket 函数的 IP 参数是否为格式正确的 IP 地址)
2
maganap
15 年前
你好!

对于 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
3
jerrywilborn at gmail dot com
14 年前
这将打印来自真正的“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);

}
3
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)//...
?>
4
greg at mtechsolutions dot ca
21 年前
如果您使用的是非阻塞,请确保不要在连接之前将其打开,否则您将收到消息

PHP 警告:socket_connect() 无法连接 [115]:操作正在进行中,位于 file.php 的第 123 行

并且 socket_connect() 将返回 false(即使它会连接)。
2
peter at videoripper dot org
14 年前
这将为您提供一个简单的端口检查器。

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

在 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.
1
vshih at yahoo
15 年前
rbarnes 的提示很有帮助,但我发现我需要在 while 循环中添加对 SOCKET_EISCONN 的检查

...
$error = socket_last_error();

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

至少在 Mac OS X 10.5 上是这样。
1
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;
}
?>
0
thewanderer
13 年前
请注意,从 PHP5.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 来实现多播器。
-2
seymour@itsyourdomain
20 年前
以下是如何使用套接字函数实现超时的示例。

此示例适用于阻塞套接字,但稍加修改即可适用于阻塞和非阻塞套接字。在非阻塞模式下,第一次调用 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");
?>
-7
logan at voerthegame dot com
22 年前
我在超时方面遇到了同样的问题,我应用了这个解决方案。

它只在 Linux PHP 上有效,我在连接套接字之前对 IP 进行 ping 操作......

<?php
$address
= gethostbyname ($ip);
$command = "ping -c 1 " . $address;
$r = exec($command);
if (
$r[0]=="r")
{
$socket = socket_create (AF_INET, SOCK_STREAM, 0);
if (
$socket < 0) {
echo
"socket_create() 失败:原因:" . socket_strerror ($socket) . "\n";
} else {
echo
"OK。\n";
}
?>
-7
telefoontoestel at home
20 年前
回复“net_del at freemail dot ru”发布的函数 socket_raw_connect。在该函数中,您给出了一个返回值,然后尝试关闭连接。这将永远不会生效。我认为您需要更改代码 ;-)
-10
mike at fserve dot us
16 年前
这可能听起来像是常识,但这是我问过的任何人都没有想到的……您不能将套接字绑定到本地主机,您必须将其绑定到路由器分配给您的 IP 或您的公共 IP 地址。如果您绑定到本地主机,它将给出无效资源错误。
To Top