socket_accept
(PHP 4 >= 4.1.0, PHP 5)
socket_accept — Aceita uma conexão com um socket
Descrição
Após o socket socket ter sido criado usando socket_create(), passar um nome com socket_bind(), e dizer para listar conexões com socket_listen(), essa função irá aceitar conexões vindas neste socket. Uma vez que uma conexão com sucesso é feita, um novo "resource" do socket é retornado, que deve ser usado para comunicação. Se há múltiplas conexões na fila do socket, a primeira irá ser usada. Se não há conexões pendentes, socket_accept() irá bloquear até que uma conexão esteja presente. Se socket não for desbloqueado usando socket_set_blocking() ou socket_set_nonblock(), irá retornar FALSE.
O socket resource retornado por socket_accept() não deve ser usado para aceitar novas conexões. A escuta original, socket, de qualquer modo, permanecer aberta e deve ser reutilizada.
Parâmetros
- socket
-
Um válido resource de socket criado com socket_create().
Valor Retornado
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() para pegar uma explicação textual do erro.
Veja Também
- socket_connect() - Inicializa uma conexão em um socket
- socket_listen() - Abre escuta para uma conexão no socket
- socket_create() - Cria um socket (endpoint para comunicação)
- socket_bind() - Passa um nome para o socket
- socket_strerror() - Retorna uma string descrevendo o erro do socket
User Contributed Notes
Beware 'socket_accept' does not return false; instead it returns NULL on error:
<?php
# accept the client and create a new socket
if (($new_socket = @socket_accept($master_socket))===false) {
echo "I should be here; but I'm not.";
}
var_dump($master_socket);
var_dump($new_socket);
?>
==================
CLI OUTPUT:
array(1) {
[0]=>
resource(20) of type (Socket)
}
NULL
==================
Where $master_socket should be a single resource.
If you want to know the remote address ( ip address ) and the port of an incoming connection that has been accepted with socket_accept(), you can use socket_getpeername()
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;
}
}
?>
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();
}
}
?>
socket_accept with timeout, seems to work for me on Apache/1.3.37 (FreeBSD 6.0) PHP/4.4.7.
Adapted from ScriptBlue at nyc dot rr dot com's post under socket_connect.
<?php
$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
socket_bind($socket,$address,$port);
socket_listen($socket);
echo "Waiting for a connection\n";
$conn = false;
switch(@socket_select($r = array($socket), $w = array($socket), $e = array($socket), 60)) {
case 2:
echo "Connection refused\n";
break;
case 1:
echo "Connection accepted\n";
$conn = @socket_accept($socket);
break;
case 0:
echo "Connection timed out\n";
break;
}
if ($conn !== false) {
// communicate over $conn
}
?>
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.
>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
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.
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!