文字

stream_socket_server

(PHP 5)

stream_socket_serverCreate an Internet or Unix domain server socket

说明

resource stream_socket_server ( string $local_socket [, int &$errno [, string &$errstr [, int $flags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN [, resource $context ]]]] )

Creates a stream or datagram socket on the specified local_socket.

This function only creates a socket, to begin accepting connections use stream_socket_accept() .

参数

local_socket

The type of socket created is determined by the transport specified using standard URL formatting: transport://target.

For Internet Domain sockets ( AF_INET ) such as TCP and UDP, the target portion of the remote_socket parameter should consist of a hostname or IP address followed by a colon and a port number. For Unix domain sockets, the target portion should point to the socket file on the filesystem.

Depending on the environment, Unix domain sockets may not be available. A list of available transports can be retrieved using stream_get_transports() . See 所支持的套接字传输器(Socket Transports)列表 for a list of bulitin transports.

errno

If the optional errno and errstr arguments are present they will be set to indicate the actual system level error that occurred in the system-level socket(), bind(), and listen() calls. If the value returned in errno is 0 and the function returned FALSE , it is an indication that the error occurred before the bind() call. This is most likely due to a problem initializing the socket. Note that the errno and errstr arguments will always be passed by reference.

errstr

See errno description.

flags

A bitmask field which may be set to any combination of socket creation flags.

Note:

For UDP sockets, you must use STREAM_SERVER_BIND as the flags parameter.

context

返回值

Returns the created stream, or FALSE on error.

范例

Example #1 Using TCP server sockets

<?php
$socket 
stream_socket_server ( "tcp://0.0.0.0:8000" $errno $errstr );
if (!
$socket ) {
  echo 
" $errstr  ( $errno )<br />\n" ;
} else {
  while (
$conn  stream_socket_accept ( $socket )) {
    
fwrite ( $conn 'The local time is '  date ( 'n/j/Y g:i a' ) .  "\n" );
    
fclose ( $conn );
  }
  
fclose ( $socket );
}
?>

The example below shows how to act as a time server which can respond to time queries as shown in an example on stream_socket_client() .

Note: Most systems require root access to create a server socket on a port below 1024.

Example #2 Using UDP server sockets

<?php
$socket 
stream_socket_server ( "udp://127.0.0.1:1113" $errno $errstr STREAM_SERVER_BIND );
if (!
$socket ) {
    die(
" $errstr  ( $errno )" );
}

do {
    
$pkt  stream_socket_recvfrom ( $socket 1 0 $peer );
    echo 
" $peer \n" ;
    
stream_socket_sendto ( $socket date ( "D M j H:i:s Y\r\n" ),  0 $peer );
} while (
$pkt  !==  false );

?>

注释

Note: 当指定数值型的 IPv6 地址(例如 fe80::1)时必须用方括号将 IP 围起来——例如, tcp://[fe80::1]:80

参见

  • stream_socket_client() - Open Internet or Unix domain socket connection
  • stream_set_blocking() - 为资源流设置阻塞或者阻塞模式
  • stream_set_timeout() - Set timeout period on a stream
  • fgets() - 从文件指针中读取一行
  • fgetss() - 从文件指针中读取一行并过滤掉 HTML 标记
  • fwrite() - 写入文件(可安全用于二进制文件)
  • fclose() - 关闭一个已打开的文件指针
  • feof() - 测试文件指针是否到了文件结束的位置
  • Curl extension

用户评论:

[#1] Aurelien Marchand [2011-03-11 11:54:10]

In the case of AF_UNIX sockets, note the named sockets that will be created respects your umask(). So if you wanted your named socket to be writeable to all, do umask(0) prior to calling stream_socket_server().

AM

[#2] frxstrem [2010-06-26 10:18:17]

Using the OpenSSL extension, PHP can automatically generate self-signed SSL certificates, which can be used for basic authentication and encryption (although I would recommend to use a signed certificate instead) for SSL servers.

I have extended the script by 'e at osterman dot com' to automatically create self-signed certificates:

<?php
// Hello World! SSL HTTP Server.
// Tested on PHP 5.1.2-1+b1 (cli) (built: Mar 20 2006 04:17:24)

// Certificate data:
$dn = array(
    
"countryName" => "UK",
    
"stateOrProvinceName" => "Somerset",
    
"localityName" => "Glastonbury",
    
"organizationName" => "The Brain Room Limited",
    
"organizationalUnitName" => "PHP Documentation Team",
    
"commonName" => "Wez Furlong",
    
"emailAddress" => "wez@example.com"
);

// Generate certificate
$privkey openssl_pkey_new();
$cert    openssl_csr_new($dn$privkey);
$cert    openssl_csr_sign($certnull$privkey365);

// Generate PEM file
# Optionally change the passphrase from 'comet' to whatever you want, or leave it empty for no passphrase
$pem_passphrase 'comet';
$pem = array();
openssl_x509_export($cert$pem[0]);
openssl_pkey_export($privkey$pem[1], $pem_passphrase);
$pem implode($pem);

// Save PEM file
$pemfile './server.pem';
file_put_contents($pemfile$pem);

$context stream_context_create();

// local_cert must be in PEM format
stream_context_set_option($context'ssl''local_cert'$pemfile);
// Pass Phrase (password) of private key
stream_context_set_option($context'ssl''passphrase'$pem_passphrase);

stream_context_set_option($context'ssl''allow_self_signed'true);
stream_context_set_option($context'ssl''verify_peer'false);

// Create the server socket
$server stream_socket_server('ssl://0.0.0.0:9001'$errno$errstrSTREAM_SERVER_BIND|STREAM_SERVER_LISTEN$context);

while(
true)
{
    
$buffer '';
    print 
"waiting...";
    
$client stream_socket_accept($server);
    print 
"accepted " stream_socket_get_name$clienttrue) . "\n";
    if( 
$client )
    {
        
// Read until double CRLF
        
while( !preg_match('/\r?\n\r?\n/'$buffer) )
            
$buffer .= fread($client2046); 
        
// Respond to client
        
fwrite($client,  "200 OK HTTP/1.1\r\n"
                         
"Connection: close\r\n"
                         
"Content-Type: text/html\r\n"
                         
"\r\n"
                         
"Hello World! " microtime(true)
                         . 
"<pre>{$buffer}</pre>");
        
fclose($client);
    } else {
        print 
"error.\n";
    }
}

?>

[#3] peterjb at me dot com [2010-01-02 03:48:08]

I had a horrible time trying to shove a TLS socket into an existing TCP program.  It appears to me that functions like stream_socket_recvfrom and stream_socket_sendto don't work with TLS/SSL (which may be obvious to PHP gurus...sorry if it is, I'm in a bit over my head here).

In the end I ended up doing all my IO with fread() and fwrite(), which solved all my problems.

[#4] davidm at marketo dot com [2009-11-22 16:15:47]

In some specialized scenarios, you may want to create an AF_INET socket (UDP or TCP) but let the system select an unused port for you.  This is a standard feature of internet sockets but it doesn't seem to be documented how to do this for the stream_socket_server function.  It appears you can get this behavior by selecting zero for the port number, for example, my test below printed "127.0.0.1:4960".

<?php
  $sock 
stream_socket_server("udp://127.0.0.1:0"); 
  
$name stream_socket_get_name($sock);
  echo 
$name;
?>

[#5] Julien Picalausa [2009-05-24 01:27:31]

You may have noticed that, unlike socket_listen, stream_socket_server doesn't have a backlog parameter. From the source code of php 5.2.9, it looks like the backlog parameter to the actual listen call is hardcoded to be 5. If this value doesn't suit your needs, you'll have to use the lower-level socket functions.

[#6] Neil Munro [2006-07-05 13:26:20]

If you want a high speed socket server, use the low-level sockets instead (socket_create/bind/listen). The stream_socket_server version appears to have internal fixed 8k buffers that will overflow if you don't keep up by reading.

This is a serious problem if you an application that reads the socket for messages and then, say, saves the result in a database. The delay while it is busy processing means you can't read the data in time unless you get involved in muti-threading.

With the the low-level functions, the OS quietly buffers TCP/IP packets so there is no problem (tested on Windows XP Professional).

[#7] andrey at php dot net [2004-08-07 21:02:49]

Just a small example how to use this function and also stream_select() to make a server that accepts more than one connections (can have many clients connected):
In master we hold all opened connections. Just before calling stream select we copy the array to $read and then pass it ot stream_select(). In case that we may read from at least one socket, $read will contain socket descriptors. $master is needed not to lose references to the opened connections we have.
stream_server.php : 
<?php

$master 
= array();
$socket stream_socket_server("tcp://0.0.0.0:8000"$errno$errstr);
if (!
$socket) {
    echo 
"$errstr ($errno)<br />\n";
} else {
    
$master[] = $socket;
    
$read $master;
    while (
1) {
        
$read $master;
        
$mod_fd stream_select($read$_w NULL$_e NULL5);
        if (
$mod_fd === FALSE) {
            break;
        }
        for (
$i 0$i $mod_fd; ++$i) {
            if (
$read[$i] === $socket) {
                
$conn stream_socket_accept($socket);
                
fwrite($conn"Hello! The time is ".date("n/j/Y g:i a")."\n");
                
$master[] = $conn;
            } else {
                
$sock_data fread($read[$i], 1024);
                
var_dump($sock_data);
                if (
strlen($sock_data) === 0) { // connection closed
                    
$key_to_del array_search($read[$i], $masterTRUE);
                    
fclose($read[$i]);
                    unset(
$master[$key_to_del]);
                } else if (
$sock_data === FALSE) {
                    echo 
"Something bad happened";
                    
$key_to_del array_search($read[$i], $masterTRUE);
                    unset(
$master[$key_to_del]);
                } else {
                    echo 
"The client has sent :"var_dump($sock_data);
                    
fwrite($read[$i], "You have sent :[".$sock_data."]\n");
                    
fclose($read[$i]);
                     unset(
$master[array_search($read[$i], $master)]);
                }
            }
        }
    }
}
?>

stream_client.php:
<?php
$fp 
stream_socket_client("tcp://127.0.0.1:8000"$errno$errstr30);
if (!
$fp) {
    echo 
"$errstr ($errno)<br />\n";
} else {
    
fwrite($fp"Aloha");
    while (!
feof($fp)) {
        
var_dump(fgets($fp1024));
    }
    
fclose($fp);
}
?>


Thanks

上一篇: 下一篇: