stream_socket_server

(PHP 5, PHP 7)

stream_socket_serverСоздаёт интернет-сокет или доменный сокет Unix

Описание

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

Создаёт потоковый или датаграммный сокет на указанном local_socket.

Эта функция только создаёт сокет. Чтобы начать принимать соединения используйте stream_socket_accept().

Список параметров

local_socket

Тип создаваемого сокета определяется по транспорту, указанному с использованием стандартного форматирования URL: transport://target.

Для доменных сокетов интернета (AF_INET), таких, как TCP и UDP, часть target параметра remote_socket должна состоять из имени хоста или IP-адреса с последующим двоеточием и номера порта. Для доменных сокетов Unix часть target должна указывать на файл сокета в файловой системе.

В зависимости от окружения, доменные сокеты Unix могут быть недоступны. Список доступных транспортов может быть получен при помощи функции stream_get_transports(). Смотрите Список поддерживаемых транспортных протоколов для списка встроенных транспортов.

errno

Если необязательные аргументы errno и errstr присутствуют, то они будут установлены для указания действительного уровня системной ошибки, которая происходит при системных вызовах socket(), bind() и listen(). Если значение, возвращаемое в errno, равно 0 и функция возвратила FALSE, это означает, что ошибка произошла до вызова bind(). Скорее всего это произошло из-за проблемы инициализации сокета. Примите во внимание, что аргументы errno и errstr должны всегда передаваться по ссылке.

errstr

Смотрите описание параметра errno.

flags

Битовая маска, которая может быть установлена в любую комбинацию флагов для создания сокета.

Замечание:

Для UDP-сокетов вы должны использовать STREAM_SERVER_BIND в качестве параметра flags.

context

Возвращаемые значения

Возвращает созданный поток, или FALSE в случае ошибки.

Примеры

Пример #1 Пример использования серверных сокетов TCP

<?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'Локальное время ' date('n/j/Y g:i a') . "\n");
    
fclose($conn);
  }
  
fclose($socket);
}
?>

Пример ниже показывает, как работать в качестве сервера времени, который может отвечать на запросы времени, как показано в примере функции stream_socket_client().

Замечание: Большинство систем требуют доступа с правами root для создания серверного сокета на порту ниже, чем 1024.

Пример #2 Пример использования серверных сокетов UDP

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

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

?>

Примечания

Замечание: При указании числового адреса IPv6 (например, fe80::1) вы должны заключать его в квадратные скобки. Например, tcp://[fe80::1]:80.

Смотрите также

  • stream_socket_client() - Открывает соединение с интернет-сокетом или с доменным сокетом Unix
  • stream_set_blocking() - Устанавливает блокирующий/неблокирующий режим на потоке
  • stream_set_timeout() - Устанавливает значение тайм-аута на потоке
  • fgets() - Читает строку из файла
  • fgetss() - Прочитать строку из файла и отбросить HTML-теги
  • fwrite() - Бинарно-безопасная запись в файл
  • fclose() - Закрывает открытый дескриптор файла
  • feof() - Проверяет, достигнут ли конец файла
  • Расширение curl

Коментарии

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
2004-08-08 00:02:49
http://php5.kiev.ua/manual/ru/function.stream-socket-server.html
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;
?>
2009-11-22 18:15:47
http://php5.kiev.ua/manual/ru/function.stream-socket-server.html
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.
2010-01-02 05:48:08
http://php5.kiev.ua/manual/ru/function.stream-socket-server.html
Автор:
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";
    }
}

?>
2010-06-26 13:18:17
http://php5.kiev.ua/manual/ru/function.stream-socket-server.html
I'm writing an HTTP server and I need SSL support, but getting this to work correctly with PHP streams took a bit of trial and error. For anyone who is trying to get an HTTP SSL server working with stream_socket_server:

1) Your SSL context will need to contain 'local_cert'. If  you did not include your private key with your local_cert, you'll also need to specify 'local_pk' which is your RSA key.  Your keys and certs should be PEM encoded, which means base-64. If your certificate has intermediary certs, you will need to specify those in the correct order: Your signed cert, intermediary cert 1, intermediary cert 2, etc. Each cert in the list needs to validate the one above it, but you do not need to include the CA Root that your SSL signer provided; that should already be included with the client's software (i.e. trust root certs).

You can append your private key in the file with your certs, however I keep mine in its own file. If you see the word "encrypted" when you view your key with a text viewer, you need to enter the correct passphrase and specify the context "passphrase", otherwise you can leave that one out.

As a server, verify_peer is irrelevant and should be set to false (should always be true if you are acting as an SSL client). Both cafile and capath contexts are not needed for functioning as a SSL/TLS server, but they are needed if you are making SSL connections with PHP as the client.

Lastly, the 'ciphers' context should be set to a list of secure ciphers. Search for "mozilla recommended ciphers" and choose the string of ciphers that works for you, because not all openssl supported ciphers are secure. I went with the "intermediate" list, which provides high security and compatibility.

2) When you create the binding for stream_socket_server(), make sure that you choose the tcp:// wrapper. DO NOT USE ssl:// or tls://. Anything other than tcp:// will not work correctly AS A SERVER, those transports are what you use when making connections with PHP as a client. 

Remember that the encryption does not start until after an SSL handshake completes, so the server has to listen in non-encrypted mode for new connections, and encryption doesn't start until certs are exchanged and a cipher is selected. When a new connection arrives you accept it with stream_socket_accept() and then use stream_socket_enable_crypto() to start the SSL session.

3) Keep in mind that the SSL handshake takes time, and that the stream_socket wrappers are high level and not as responsive as the socket extension due to the additional overhead they incur. For this reason you will need to enable blocking for accepting new connections.

<enable blocking on ServerListenStream>
newConnStream = stream_socket_accept(ServerListenStream);
<disable blocking on ServerListenStream>

<enable blocking on newConnStream >
stream_socket_enable_crypto(newConnStream, true, STREAM_CRYPTO_METHOD_SSLv23_SERVER);
<disable blocking on newConnStream >

Note that this is mainly for HTTP. If you are trying to do something like SMTP then your script will have to react to the "starttls" command, but it would be similar to the above except that you would wait for the "starttls" command before invoking the  stream_socket_enable_crypto() function on the client's stream.

TLS 1.0 is generally the way to go, SSLv3 is insecure and SSLv2 is buggy. If you use the mozilla recommend cipher list in your context, you'll be fine. Hope this helps someone out!
2015-12-03 15:35:13
http://php5.kiev.ua/manual/ru/function.stream-socket-server.html
This is an example of how to set up stream_socket_server to connect with multiple Secure Websockets on WSS (wss://) that uses SSL / TLS as a Transport. 

This runs on a Windows Apache Server with a registered domain and SSL Cert from LetsEncrypt via Certbot.

Run this script from a console "php server.php", and javascript html as a client with:
socket = new WebSocket('wss://php.net:1234');

<?php
$host 
'192.168.1.2';
$port 1234;
$path 'C:/Certbot/live/php.net/';
$transport 'tlsv1.3';
$ssl = ['ssl' => [
         
'local_cert'  => $path 'cert.pem',       // SSL Certificate
         
'local_pk'    => $path 'privkey.pem',    // SSL Keyfile
         
'disable_compression' => true,             // TLS compression attack vulnerability
         
'verify_peer'         => false,            // Set this to true if acting as an SSL client
         
'ssltransport' => $transport,              // Transport Methods such as 'tlsv1.1', tlsv1.2' 
       
] ];
$ssl_context stream_context_create($ssl);
$server stream_socket_server($transport '://' $host ':' $port$errno$errstrSTREAM_SERVER_BIND|STREAM_SERVER_LISTEN$ssl_context);
if (!
$server) {  die("$errstr ($errno)"); } 
$clients = array($server);
$write  NULL;
$except NULL;
while (
true) {
 
$changed $clients;
 
stream_select($changed$write$except10);
  if (
in_array($server$changed)) {
   
$client = @stream_socket_accept($server);
    if (!
$client){ continue; }
   
$clients[] = $client;
   
$ip stream_socket_get_name$clienttrue );
    echo 
"New Client connected from $ip\n";
   
   
stream_set_blocking($clienttrue);
   
$headers fread($client1500);
   
handshake($client$headers$host$port);
   
stream_set_blocking($clientfalse);

   
send_message($clientsmask($ip ' connected'));
   
$found_socket array_search($server$changed);
    unset(
$changed[$found_socket]);     
  }
  foreach (
$changed as $changed_socket) {
   
$ip stream_socket_get_name$changed_sockettrue );
   
$buffer stream_get_contents($changed_socket);
        if (
$buffer == false) {
      echo 
"Client Disconnected from $ip\n";
      @
fclose($changed_socket);
           
$found_socket array_search($changed_socket$clients);
            unset(
$clients[$found_socket]);
        }
   
$unmasked unmask($buffer);
    if (
$unmasked != "") { echo "\nReceived a Message from $ip:\n\"$unmasked\" \n"; }
   
$response mask($unmasked);
   
send_message($clients$response);
  }
}
fclose($server);

function 
unmask($text) {
   
$length = @ord($text[1]) & 127;
    if(
$length == 126) {    $masks substr($text44);    $data substr($text8); }
    elseif(
$length == 127) {    $masks substr($text104); $data substr($text14); }
    else { 
$masks substr($text24); $data substr($text6); }
   
$text "";
    for (
$i 0$i strlen($data); ++$i) { $text .= $data[$i] ^ $masks[$i 4];    }
    return 
$text;
}
function 
mask($text) {
   
$b1 0x80 | (0x1 0x0f);
   
$length strlen($text);
    if(
$length <= 125)
       
$header pack('CC'$b1$length);
    elseif(
$length 125 && $length 65536)
       
$header pack('CCn'$b1126$length);
    elseif(
$length >= 65536)
       
$header pack('CCNN'$b1127$length);
    return 
$header.$text;
}
function 
handshake($client$rcvd$host$port){
   
$headers = array();
   
$lines preg_split("/\r\n/"$rcvd);
    foreach(
$lines as $line)
    {
       
$line rtrim($line);
        if(
preg_match('/\A(\S+): (.*)\z/'$line$matches)){
           
$headers[$matches[1]] = $matches[2];
        }
    }
   
$secKey $headers['Sec-WebSocket-Key'];
   
$secAccept base64_encode(pack('H*'sha1($secKey '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
   
//hand shaking header
   
$upgrade  "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .
   
"Upgrade: websocket\r\n" .
   
"Connection: Upgrade\r\n" .
   
"WebSocket-Origin: $host\r\n" .
   
"WebSocket-Location: wss://$host:$port\r\n".
   
"Sec-WebSocket-Version: 13\r\n" .
   
"Sec-WebSocket-Accept:$secAccept\r\n\r\n";
 
fwrite($client$upgrade);
}
function 
send_message($clients$msg){
    foreach(
$clients as $changed_socket){
    @
fwrite($changed_socket$msg);
    }
}
?>
2020-11-25 09:27:24
http://php5.kiev.ua/manual/ru/function.stream-socket-server.html

    Поддержать сайт на родительском проекте КГБ