socket_accept
(PHP 4 >= 4.1.0, PHP 5)
socket_accept — Accepts a connection on a socket
Description
$socket
)
After the socket socket
has been created
using socket_create(), bound to a name with
socket_bind(), and told to listen for connections
with socket_listen(), this function will accept
incoming connections on that socket. Once a successful connection
is made, a new socket resource is returned, which may be used
for communication. If there are multiple connections queued on
the socket, the first will be used. If there are no pending
connections, socket_accept() will block until
a connection becomes present. If socket
has been made non-blocking using
socket_set_blocking() or
socket_set_nonblock(), FALSE
will be returned.
The socket resource returned by
socket_accept() may not be used to accept new
connections. The original listening socket
socket
, however, remains open and may be
reused.
Return Values
Returns a new socket resource on success, or FALSE
on error. The actual
error code can be retrieved by calling
socket_last_error(). This error code may be passed to
socket_strerror() to get a textual explanation of the
error.
See Also
- socket_connect() - Initiates a connection on a socket
- socket_listen() - Listens for a connection on a socket
- socket_create() - Create a socket (endpoint for communication)
- socket_bind() - Binds a name to a socket
- socket_strerror() - Return a string describing a socket error
- socket_accept
- socket_bind
- socket_clear_error
- socket_close
- socket_cmsg_space
- socket_connect
- socket_create_listen
- socket_create_pair
- socket_create
- socket_get_option
- socket_getopt
- socket_getpeername
- socket_getsockname
- socket_import_stream
- socket_last_error
- socket_listen
- socket_read
- socket_recv
- socket_recvfrom
- socket_recvmsg
- socket_select
- socket_send
- socket_sendmsg
- socket_sendto
- socket_set_block
- socket_set_nonblock
- socket_set_option
- socket_setopt
- socket_shutdown
- socket_strerror
- socket_write
Коментарии
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.
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.
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();
}
}
?>
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;
}
}
?>
<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 ^_^