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
stream_socket_server
(PHP 5)
stream_socket_server — Crear un socket de servidor de dominio de Internet o de Unix
Descripción
Crea un socket de flujo o de datagrama en local_socket.
Esta función sólo crea un socket, para empezar a aceptar conexiones use stream_socket_accept().
Parámetros
- local_socket
-
El tipo de socket creado se determina por el transporte especificado usando el formato de URL estándar: transporte://objetivo.
Para sockets de Dominio de Internet (AF_INET) como TCP y UDP, la porción del objetivo del parámetro remote_socket debería consistir en un nombre de host o dirección IP seguida de dos puntos y un número de puerto. Para sockets de dominio de Unix, la porción del objetivo apuntará al archivo de socket del sistema de archivos.
Dependiendo del entorno, los sockets de dominio Unix pueden no estar disponibles. Una lista de transportes disponibles se puede recuperar unsado stream_get_transports(). Véase Lista de Transportes de Sockets Soportados para una lista de transportes incluidos.
- errno
-
Si los argumentos opcionales errno y errstr están presentes, serán establecidos para indicar el error a nivel de sistema ocurrido en las llamadas a nivel de sistema de socket(), bind(), y listen(). Si el valor devuelto en errno es 0 y la función devuelve FALSE, es una indicación de que el error ocurrió antes de la llamada a bind(). Esto es lo más probable debido a un problema de inicialización del socket. Observe que los argumentos errno y errstr siempre serán pasados por referencia.
- errstr
-
Véase la descripción de errno.
- flags
-
Campo de máscara de bits que puede ser establecido a cualquier combinación de banderas de conexión.
Note:
Para sockets UDP, se debe usar STREAM_SERVER_BIND como parámetro flags.
- context
-
Valores devueltos
Devuelve un flujo creado, o FALSE si se produjo un error.
Ejemplos
Example #1 Usar sockets de servidor de 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, 'La fecha y hora actuales es ' . date('n/j/Y g:i a') . "\n");
fclose($conn);
}
fclose($socket);
}
?>
El ejemplo de abajo muestra cómo actuar como un servidor de hora que responde a peticiones de hora como se muestra en un ejemplo de stream_socket_client().
Note: La mayoría de los sistemas requieren acceso root para crear un socket de servidor sobre un puerto inferor a 1024.
Example #2 Usar sockets de servidor de UDP
<?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);
?>
Notas
Note: Cuando se especifique una dirección numérica IPv6 (por ej., fe80::1), la IP debe ser encerrada entre corchetes — por ejemplo, tcp://[fe80::1]:80.
Ver también
- stream_socket_client() - Abrir una conexión de socket de dominio de Internet o Unix
- stream_set_blocking() - Establecer el modo bloqueo/no-bloqueo en un flujo
- stream_set_timeout() - Establecer un perido de tiempo de espera en un flujo
- fgets() - Obtiene un línea del puntero a un archivo
- fgetss() - Obtiene un línea desde un puntero a un archivo y elimina las etiquetas HTML
- fwrite() - Escritura de un archivo en modo binario seguro
- fclose() - Cierra un puntero a un archivo abierto
- feof() - Comprueba si el puntero a un archivo está al final del archivo
- La extensión Curl
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($cert, null, $privkey, 365);
// 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, $errstr, STREAM_SERVER_BIND|STREAM_SERVER_LISTEN, $context);
while(true)
{
$buffer = '';
print "waiting...";
$client = stream_socket_accept($server);
print "accepted " . stream_socket_get_name( $client, true) . "\n";
if( $client )
{
// Read until double CRLF
while( !preg_match('/\r?\n\r?\n/', $buffer) )
$buffer .= fread($client, 2046);
// 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";
}
}
?>
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.
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;
?>
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.
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).
Example "Hello World!" SSL HTTP Server. Note, if you don't use a signed ssl certificate, your browser will give you a warning.
<?php
// Hello World! SSL HTTP Server.
// Tested on PHP 5.1.2-1+b1 (cli) (built: Mar 20 2006 04:17:24)
$context = stream_context_create();
// local_cert must be in PEM format
stream_context_set_option($context, 'ssl', 'local_cert', './server.pem');
// Pass Phrase (password) of private key
stream_context_set_option($context, 'ssl', 'passphrase', 'comet');
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, $errstr, STREAM_SERVER_BIND|STREAM_SERVER_LISTEN, $context);
while(true)
{
$buffer = '';
print "waiting...";
$client = stream_socket_accept($server);
print "accepted " . stream_socket_get_name( $client, true) . "\n";
if( $client )
{
// Read until double CRLF
while( !preg_match('/\r?\n\r?\n/', $buffer) )
$buffer .= fread($client, 2046);
// 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";
}
}
// Example PEM File below (call it server.pem, to use this example)
// Use these instructions to create your own. http://sial.org/howto/openssl/self-signed/
/*
-----BEGIN CERTIFICATE-----
MIIDgTCCAuqgAwIBAgIJAMgtIWVzb1oIMA0GCSqGSIb3DQEBBQUAMIGIMQswCQYD
VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEUMBIGA1UEBxMLTG9zIEFuZ2Vs
ZXMxFDASBgNVBAoTC091ciBDb21wYW55MQ0wCwYDVQQLEwRUZXN0MQwwCgYDVQQD
EwNEZXYxGzAZBgkqhkiG9w0BCQEWDGFzZEBob3N0LmNvbTAeFw0wNjA1MjYwMTM4
NTRaFw0wNzA1MjYwMTM4NTRaMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2Fs
aWZvcm5pYTEUMBIGA1UEBxMLTG9zIEFuZ2VsZXMxFDASBgNVBAoTC091ciBDb21w
YW55MQ0wCwYDVQQLEwRUZXN0MQwwCgYDVQQDEwNEZXYxGzAZBgkqhkiG9w0BCQEW
DGFzZEBob3N0LmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3mStTm74
kOQCelquoGI/WyUIOvngDdNcJGmi2xnzDpRjKfQTH/3VVDQJUwvjKcLxnBQHFg7M
nvEZrfC3LEmFajAzRKjXK5gUCQEQKqhbVsfZO+7ANq4axNldd4UgMhPeZIKr8DDt
P3pjFqFSYh/dtOq2pfDXSbstmCZ1Q3GAYDcCAwEAAaOB8DCB7TAdBgNVHQ4EFgQU
WQSzc00pkM9aCzsxKJpTYm3kwEUwgb0GA1UdIwSBtTCBsoAUWQSzc00pkM9aCzsx
KJpTYm3kwEWhgY6kgYswgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9y
bmlhMRQwEgYDVQQHEwtMb3MgQW5nZWxlczEUMBIGA1UEChMLT3VyIENvbXBhbnkx
DTALBgNVBAsTBFRlc3QxDDAKBgNVBAMTA0RldjEbMBkGCSqGSIb3DQEJARYMYXNk
QGhvc3QuY29tggkAyC0hZXNvWggwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUF
AAOBgQA7G/XKQ9kLTZOcVAG/IOxdn9tW38sEwHifNQ7zMSS5di1MmnD5JJWdK/s4
dzN06T1Ey5FCu2kafFzk48khZpoPsXMRF8DNBXLVSCGj4maPtEviJVjwtj3XwZjA
82a8A/Yil0+fo25zPX4I4oBcbl3bPqzVPXxsQ7myp9f7MDZcbQ==
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,E4476A175B6608B6
r0sox8H5ijuOanXwYFtIDgPti3AAuIUdy5EJG9GZbrtQHEW6HL+YxdI58Ng70t4w
EfBvcuLb7XAGsJwF65yad0vSXsYv6F+0brEefEvZX3ljxUZ3yGfHVJyEdBWJty7X
A8QpqOVVQseAST1IKeWOIT16/a9ZOgwnIhQe36y43pxBwL5tumXTM+AuWPOBW8c0
s49I8GyptttGJpcFohLsmP9Jza/fMIzYFNeuOBQ93fieCcVXBd2fWNyZVEsOU5Mi
kt5FQ9Lc9F8Wc+Mh0xiodDz6H+2yNIMC2SNu/mDSAGwDCctBZ34enFDad/eBiYW+
iTjMaqWGFs+cantSgVQ6pdZWYQd5Rsb3/Qbcfia/C1vtzWipBG7wlQCsNWwceXx/
f8hqWl5kyCxvBdH9eyRNMVJkCbFABl9tnaMGRi/UnVL68wgUvosAsdCjUrdL3x7O
i6yMBrxYjACbYslPFaG5OtgXcbacBKjsVMkcRYRyGqClgVZHICYZXhZoZTjOsgT4
L9WivT1RnozmFUMPaXbnxX4h/B3v6aSYAc4mPM6oMFTiXGJ7cLoafNw7Fxug7oeF
0+04DykzFCsLw1PmnkXP/WliQ+xidKJeKl2bR0k5MjAs0ksjelk7hAbCDjE0ct0w
LAHuvf6haClaFBa0ugL90S6BBdIQad9GRmAqZlVc5tANZleXFEY2wKUSMddIKzsm
nouipBWt3flDyYaFRtF20IYYk59z3zlqk73U/cFRkpT9SvHbxdsjTX1OvsmuhMzV
5K4+1QaBK4vePOFeEHDAkwGGqI1Wj+2lC6pxdLe3tjIzNWN1eaq59Q==
-----END RSA PRIVATE KEY-----
*/
?>
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 = NULL, 5);
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], $master, TRUE);
fclose($read[$i]);
unset($master[$key_to_del]);
} else if ($sock_data === FALSE) {
echo "Something bad happened";
$key_to_del = array_search($read[$i], $master, TRUE);
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, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
fwrite($fp, "Aloha");
while (!feof($fp)) {
var_dump(fgets($fp, 1024));
}
fclose($fp);
}
?>
Thanks
