socket_accept

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

socket_accept接受套接字上的连接

描述

socket_accept(Socket $socket): Socket|false

在使用 socket_create() 创建套接字 socket 后,使用 socket_bind() 绑定到一个名称,并使用 socket_listen() 监听连接后,此函数将接受该套接字上的传入连接。建立成功连接后,将返回一个新的 Socket 实例,可用于通信。如果套接字上有多个连接排队,则将使用第一个连接。如果没有待处理的连接,socket_accept() 将阻塞,直到出现连接。如果 socket 已使用 socket_set_blocking()socket_set_nonblock() 设置为非阻塞,将返回 false

socket_accept() 返回的 Socket 实例不能用于接受新连接。但是,原始监听套接字 socket 仍然处于打开状态,可以重复使用。

参数

socket

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

返回值

成功时返回一个新的 Socket 实例,错误时返回 false。可以通过调用 socket_last_error() 获取实际的错误代码。此错误代码可以传递给 socket_strerror() 以获取错误的文字解释。

变更日志

版本 描述
8.0.0 成功时,此函数现在返回一个 Socket 实例;以前,返回一个 resource

参见

添加笔记

用户贡献的笔记 7 notes

lars at opdenkamp dot eu
16 年前
如果您想创建一个在每次客户端连接时都进行 fork 的守护进程,您会发现 PHP 中存在一个错误。子进程在退出时会向其父进程发送 SIGCHLD,但父进程在等待 socket_accept(阻塞)时无法处理信号。

以下代码段创建了一个非阻塞 fork 服务器。

#!/usr/bin/php -q
<?php
/**
* 监听请求并在每个连接上进行分叉
*/

$__server_listening = true;

error_reporting(E_ALL);
set_time_limit(0);
ob_implicit_flush();
declare(
ticks = 1);

become_daemon();

/* nobody/nogroup,更改为您的主机上的非特权用户的 uid/gid */
change_identity(65534, 65534);

/* 处理信号 */
pcntl_signal(SIGTERM, 'sig_handler');
pcntl_signal(SIGINT, 'sig_handler');
pcntl_signal(SIGCHLD, 'sig_handler');

/* 将其更改为您自己的主机/端口 */
server_loop("127.0.0.1", 1234);

/**
* 将身份更改为非特权用户
*/
function change_identity( $uid, $gid )
{
if( !
posix_setgid( $gid ) )
{
print
"无法将 gid 设置为 " . $gid . "!\n";
exit;
}

if( !
posix_setuid( $uid ) )
{
print
"无法将 uid 设置为 " . $uid . "!\n";
exit;
}
}

/**
* 创建一个服务器套接字并监听传入的客户端连接
* @param string $address 要监听的地址
* @param int $port 要监听的端口
*/
function server_loop($address, $port)
{
GLOBAL
$__server_listening;

if((
$sock = socket_create(AF_INET, SOCK_STREAM, 0)) < 0)
{
echo
"创建套接字失败: ".socket_strerror($sock)."\n";
exit();
}

if((
$ret = socket_bind($sock, $address, $port)) < 0)
{
echo
"绑定套接字失败: ".socket_strerror($ret)."\n";
exit();
}

if( (
$ret = socket_listen( $sock, 0 ) ) < 0 )
{
echo
"监听套接字失败: ".socket_strerror($ret)."\n";
exit();
}

socket_set_nonblock($sock);

echo
"等待客户端连接\n";

while (
$__server_listening)
{
$connection = @socket_accept($sock);
if (
$connection === false)
{
usleep(100);
}elseif (
$connection > 0)
{
handle_client($sock, $connection);
}else
{
echo
"错误: ".socket_strerror($connection);
die;
}
}
}

/**
* 信号处理程序
*/
function sig_handler($sig)
{
switch(
$sig)
{
case
SIGTERM:
case
SIGINT:
exit();
break;

case
SIGCHLD:
pcntl_waitpid(-1, $status);
break;
}
}

/**
* 处理新的客户端连接
*/
function handle_client($ssock, $csock)
{
GLOBAL
$__server_listening;

$pid = pcntl_fork();

if (
$pid == -1)
{
/* fork 失败 */
echo "fork 失败!\n";
die;
}elseif (
$pid == 0)
{
/* 子进程 */
$__server_listening = false;
socket_close($ssock);
interact($csock);
socket_close($csock);
}else
{
socket_close($csock);
}
}

function
interact($socket)
{
/* 与您的客户端通话 */
}

/**
* 通过分叉并关闭父进程成为守护进程
*/
function become_daemon()
{
$pid = pcntl_fork();

if (
$pid == -1)
{
/* fork 失败 */
echo "fork 失败!\n";
exit();
}elseif (
$pid)
{
/* 关闭父进程 */
exit();
}else
{
/* 子进程成为我们的守护进程 */
posix_setsid();
chdir('/');
umask(0);
return
posix_getpid();

}
}

?>
Boylett
16 年前
如果你想在一个服务器上拥有多个客户端,你将不得不使用非阻塞。

<?php

$clients
= array();
$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
socket_bind($socket,'127.0.0.1',$port);
socket_listen($socket);
socket_set_nonblock($socket);

while(
true)
{
if((
$newc = socket_accept($socket)) !== false)
{
echo
"客户端 $newc 已连接\n";
$clients[] = $newc;
}
}

?>
Greg MacLellan
20 年前
此资源返回的套接字将是非阻塞的,无论监听套接字设置为何种状态。这实际上适用于所有 FCNTL 修饰符。
renmengyang567 at gmail dot com
5 年前
<解释>
这种情况是 TCP 客户端和 TCP 服务器之间非常简单的交互

<?php
// 为 simple-tcp-server 创建
$sock = socket_create(AF_INET, SOCK_STREAM, getprotobyname('tcp'));
socket_bind($sock, '127.0.0.1',5000);
socket_listen($sock,1);
$clnt_sock = socket_accept($sock); // 阻塞
$st = "hello world ^_^";
socket_write($clnt_sock, $st,strlen($st));
socket_close($clnt_sock);
socket_close($sock);
?>

<?php
// 为简单 TCP 客户端创建
$clnt_sock = socket_create(AF_INET, SOCK_STREAM, getprotobyname('tcp'));
socket_connect($clnt_sock, '127.0.0.1', 5000);
$ret= socket_read($clnt_sock, 1024);
print
"来自简单 TCP 服务器:" .$ret.PHP_EOL;
socket_close($clnt_sock);
?>

<fruit>
来自简单 TCP 服务器:hello world ^_^
gmkarl at gmail dot com
17 年前
请注意,使用 pcntl_signal 设置的信号处理函数在套接字阻塞等待连接时不会被调用;信号会被静默地吸收,并在建立连接时调用处理程序。
simon at 180solutions dot com
19 年前
> 使用 php-sockets 接受连接
>
>$fd = socket_create(AF_INET, SOCK_STREAM, 6 /* 或 >getprotobyname("TCP")*/);
>
>$PORT = 5000;
>
>socket_bind($fd, "0.0.0.0", $PORT);
>
>while(true)
>{
>$remote_fd = socket_accept($fd);
>
>remote_socket_client_handle($remote_fd);
>
>}
>
>很简单!

此示例无法正常工作。您需要在 bind 后调用 socket_listen($fd) 才能接受传入的连接。

Simon
mightyplow at gmail dot com
10 年前
为了让多个客户端能够连接到服务器,您需要将接受的套接字也设置为非阻塞。否则,接受的连接将阻止进一步的传入连接。

while (true) {
$newSock = @socket_accept($sock);

if ($newSock) {
echo '客户端已连接';

socket_set_nonblock($newSock);
}
}
To Top