PHP Velho Oeste 2024

socket_accept

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

socket_accept接受套接字上的连接

说明

socket_accept(Socket $socket): Socket|false

socket 是从 socket_create() 创建,使用 socket_bind() 绑定,socket_listen() 监听的一个套接字实例。此函数接受在 socket 上创建的连接。当连接被成功创建后,返回一个可用于通信的 Socket 实例。若有多个连接排队,返回队头第一个连接。若没有待处理的连接,那么 socket_accept() 默认阻塞,直到有一个连接出现。如果 socket 使用 socket_set_blocking()socket_set_nonblock() 设置为非阻塞,那么 socket_accept() 将直接返回 false

socket_accept() 返回的 Socket 实例不能用于接受新的连接。但 socket 依然保持打开状态,并且可以继续接受新的连接。

参数

socket

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

返回值

成功时返回一个新的 Socket 实例,错误时返回 false。可以通过调用 socket_last_error() 来检索实际的错误代码。将错误代码作为参数传递给 socket_strerror() 以获得错误的文本解释。

更新日志

版本 说明
8.0.0 成功时,该函数现在返回一个 Socket 实例;在此之前,返回值是一个 resource

参见

add a note

User Contributed Notes 7 notes

up
24
lars at opdenkamp dot eu
16 years ago
If you want to make a daemon process that forks on each client connection, you'll find out that there's a bug in PHP. The child processes send SIGCHLD to their parent when they exit but the parent can't handle signals while it's waiting for socket_accept (blocking).

Here is a piece of code that makes a non-blocking forking server.

#!/usr/bin/php -q
<?php
/**
* Listens for requests and forks on each connection
*/

$__server_listening = true;

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

become_daemon();

/* nobody/nogroup, change to your host's uid/gid of the non-priv user */
change_identity(65534, 65534);

/* handle signals */
pcntl_signal(SIGTERM, 'sig_handler');
pcntl_signal(SIGINT, 'sig_handler');
pcntl_signal(SIGCHLD, 'sig_handler');

/* change this to your own host / port */
server_loop("127.0.0.1", 1234);

/**
* Change the identity to a non-priv user
*/
function change_identity( $uid, $gid )
{
if( !
posix_setgid( $gid ) )
{
print
"Unable to setgid to " . $gid . "!\n";
exit;
}

if( !
posix_setuid( $uid ) )
{
print
"Unable to setuid to " . $uid . "!\n";
exit;
}
}

/**
* Creates a server socket and listens for incoming client connections
* @param string $address The address to listen on
* @param int $port The port to listen on
*/
function server_loop($address, $port)
{
GLOBAL
$__server_listening;

if((
$sock = socket_create(AF_INET, SOCK_STREAM, 0)) < 0)
{
echo
"failed to create socket: ".socket_strerror($sock)."\n";
exit();
}

if((
$ret = socket_bind($sock, $address, $port)) < 0)
{
echo
"failed to bind socket: ".socket_strerror($ret)."\n";
exit();
}

if( (
$ret = socket_listen( $sock, 0 ) ) < 0 )
{
echo
"failed to listen to socket: ".socket_strerror($ret)."\n";
exit();
}

socket_set_nonblock($sock);

echo
"waiting for clients to connect\n";

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

/**
* Signal handler
*/
function sig_handler($sig)
{
switch(
$sig)
{
case
SIGTERM:
case
SIGINT:
exit();
break;

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

/**
* Handle a new client connection
*/
function handle_client($ssock, $csock)
{
GLOBAL
$__server_listening;

$pid = pcntl_fork();

if (
$pid == -1)
{
/* fork failed */
echo "fork failure!\n";
die;
}elseif (
$pid == 0)
{
/* child process */
$__server_listening = false;
socket_close($ssock);
interact($csock);
socket_close($csock);
}else
{
socket_close($csock);
}
}

function
interact($socket)
{
/* TALK TO YOUR CLIENT */
}

/**
* Become a daemon by forking and closing the parent
*/
function become_daemon()
{
$pid = pcntl_fork();

if (
$pid == -1)
{
/* fork failed */
echo "fork failure!\n";
exit();
}elseif (
$pid)
{
/* close the parent */
exit();
}else
{
/* child becomes our daemon */
posix_setsid();
chdir('/');
umask(0);
return
posix_getpid();

}
}

?>
up
18
Boylett
15 years ago
If you want to have multiple clients on a server you will have to use non blocking.

<?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
"Client $newc has connected\n";
$clients[] = $newc;
}
}

?>
up
4
Greg MacLellan
20 years ago
The socket returned by this resource will be non-blocking, regardless of what the listening socket is set to. This is actually true for all FCNTL modifiers.
up
2
renmengyang567 at gmail dot com
4 years ago
<explain>
This case is a very simple interaction between the TCP client side and the TCP server side

<?php
// create for 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
//create for simple-tcp-client
$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
"from simple-tcp-server:".$ret.PHP_EOL;
socket_close($clnt_sock);
?>

<fruit>
from simple-tcp-server:hello world ^_^
up
-1
gmkarl at gmail dot com
16 years ago
Be aware signal handler functions set with pcntl_signal are not called while a socket is blocking waiting for a connection; the signal is absorbed silently and the handler called when a connection is made.
up
-7
simon at 180solutions dot com
18 years ago
>Accepting a connection using php-sockets:
>
>$fd = socket_create(AF_INET, SOCK_STREAM, 6 /* OR >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);
>
>}
>
>It is simple!

This example doesn't work. You have to call socket_listen($fd) after your bind in order to accept incoming connections.

Simon
up
-8
mightyplow at gmail dot com
9 years ago
In order to make many clients connectable to the server, you have to set the accepted socket also to non-blocking. Otherwise the accepted connection will block further incoming connections.

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

if ($newSock) {
echo 'client connected';

socket_set_nonblock($newSock);
}
}
To Top