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

参见

添加备注

用户贡献的备注 5 notes

up
24
lars at opdenkamp dot eu
17 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
17 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
21 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
6 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
18 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.
To Top