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 — Crée un socket serveur Unix ou Internet
Description
$local_socket
[, int &$errno
[, string &$errstr
[, int $flags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN
[, resource $context
]]]] )
stream_socket_server() crée un flux ou un datagramme
sur le socket spécifié local_socket.
stream_socket_server() ne fait que créer un socket et, pour accepter des connexions, vous devez utiliser stream_socket_accept().
Liste de paramètres
-
local_socket -
Le type de socket créé est déterminé par le transport spécifié avec le formatage URL suivant : transport://target.
Pour un socket Internet,(
AF_INET) comme TCP et UDP, la cible deremote_socketsera une adresse IP ou un nom d'hôte suivi de deux points et d'un numéro de port. Pour un socket Unix, la cible doit être un fichier de socket du système.En fonction de votre environnement, les sockets de domaine Unix peuvent être indisponibles. Une liste des transports disponibles est accessible via stream_get_transports(). Voyez Liste des modes de transport de sockets disponibles pour connaître la liste des transports natifs.
-
errno -
Si les arguments optionnels
errnoeterrstrsont présents, ils seront configurés pour indiquer le niveau d'erreur actuel des fonctions système socket(), bind() et listen(). Si la valeur retournée danserrnoest 0, et que la fonction retourneFALSE, c'est une indication que l'erreur est survenue avant l'appel à bind(). Ceci est probablement dû à un problème d'initialisation du socket. Notez que les argumentserrnoeterrstrseront toujours passés par référence. -
errstr -
Voyez la description de
errno. -
flags -
Un champ de bits, qui peut être la combinaison de n'importe quelle option de création de socket.
Note:
Pour les sockets UDP, vous devez utiliser la constante
STREAM_SERVER_BINDcomme valeur du paramètreflags. -
context -
Valeurs de retour
Retourne le flux créé, ou bien FALSE en cas d'erreur.
Exemples
Exemple #1 Exemple avec stream_socket_server()
<?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)) {
fputs ($conn, 'L\'heure locale est ' . date('n/j/Y g:i a') . "\n");
fclose ($conn);
}
fclose($socket);
}
?>
L'exemple ci-dessous vous montre comment lire la date et l'heure sur un service UDP (port 13) sur votre propre machine, tel que présenté avec la fonction stream_socket_client() :
Note: La plupart des systèmes ont besoin d'un accès administrateur pour ouvrir un socket sur les ports en dessous de 1024.
Exemple #2 Utiliser un serveur de socket UDP
<?php
$socket = stream_socket_server("udp://0.0.0.0:13", $errno, $errstr, STREAM_SERVER_BIND);
if (!$socket) {
echo "ERROR: $errno - $errstr<br />\n";
} else {
while ($conn = stream_socket_accept($socket)) {
fwrite($conn, date("D M j H:i:s Y\r\n"));
fclose($conn);
}
fclose($socket);
}
?>
Notes
Note: Lors de la spécification d'adresses IPv6 au format numérique (e.g. fe80::1) vous devez placer l'adresse IP entre crochets. Par exemple : tcp://[fe80::1]:80.
Voir aussi
- stream_socket_client() - Ouvre une connexion socket Internet ou Unix
- stream_set_blocking() - Configure le mode bloquant d'un flux
- stream_set_timeout() - Configure la durée d'expiration d'un flux
- fgets() - Récupère la ligne courante sur laquelle se trouve le pointeur du fichier
- fgetss() - Renvoie la ligne courante du fichier et élimine les balises HTML
- fwrite() - Écrit un fichier en mode binaire
- fclose() - Ferme un fichier
- feof() - Teste la fin du fichier
- Extension 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).
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
