PHP  
downloads | documentation | faq | getting help | mailing lists | | php.net sites | links 
search for in the  
previoussnmpwalkoidsocket_acceptnext
Last updated: Tue, 09 Jul 2002
view the printer friendly version or the printer friendly version with notes or change language to English | Brazilian Portuguese | Chinese | Czech | Dutch | Finnish | German | Hungarian | Italian | Japanese | Korean | Polish | Romanian | Russian | Spanish | Swedish | Turkish

XCVI. Sockets

Avertissement

Ce module est EXPERIMENTAL. Cela signifie que le comportement de ces fonctions, leurs noms et concr�tement, TOUT ce qui est document� ici peut changer dans un futur proche, SANS PREAVIS! Soyez-en conscient, et utiliser ce module � vos risques et p�rils.

L'extension socket impl�mente une interface bas niveau avec les fonctions de communication par socket. Cela permet de mettre en place un serveur aussi bien qu'un client.

Les fonctions socket d�crites ici sont rassembl�es dans une extension PHP. Pour �tre activ�es, il faut utiliser l'option de compilation --enable-sockets au script configure.

Pour une interface client plus g�n�rique, reportez vous � fsockopen() et pfsockopen().

Lorsque vous utiliserez les fonctions de sockets qui sont d�crites ici, gardez bien � l'esprit que m�me si elles ont souvent des noms identiques aux fonctions C, elles ont souvent des prototypes diff�rents. Lisez attentivement la documentation pour �viter les confusions.

Cela dit, ceux qui n'ont pas l'habitude de la programmation avec les sockets pourront trouver beaucoup de documentation pertinente dans les pages de manuel Unix, et de nombreux tutorial de programmation C sur le web, dont la plus part peuvent �tre repris apr�s de l�g�re modifications, en PHP.

Exemple 1. Exemple de programmation Socket : serveur TCP/IP

Cet exemple est un serveur perroquete : tout ce que vous lui envoyez vous est retourn�. Changez les variables address et port pour les adapter � votre configuration, et lancez le script. Vous pouvez vous connecter au serveur avec une commande telle que telnet 192.168.1.53 10000 (avec l'adresse et le port qui sont ceux de votre configuration). Pour vous d�connecter, tapez 'quit'.

<?php
error_reporting(E_ALL);
/* On autorise le script � attendre les connexions ind�finiment. */
set_time_limit(0);
/* Modifiez ces valeurs pour qu'elles soient celles de votre configuration */
$address = '192.168.1.53';
$port = 10000;
if (($sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
    echo "socket() a �chou� : raison : " . strerror($sock) . "\n";
}
if (($ret = bind($sock, $address, $port)) < 0) {
    echo "bind() a �chou� : raison: " . strerror($ret) . "\n";
}
if (($ret = listen($sock, 5)) < 0) {
    echo "listen() a �chou� : raison: " . strerror($ret) . "\n";
}
do {
    if (($msgsock = accept_connect($sock)) < 0) {
        echo "accept_connect() a �chou� : raison : " . strerror($msgsock) . "\n";
        break;
    }
    do {
        $buf = '';
        $ret = read($msgsock, $buf, 2048);
        if ($ret < 0) {
            echo "read() a �chou� : raison : " . strerror($ret) . "\n";
            break 2;
        }
        if ($ret == 0) {
            break 2;
        }
        $buf = trim($buf);
        if ($buf == 'quit') {
            close($msgsock);
            break 2;
        }
        $talkback = "PHP: Vous avez dit '$buf'.\n";
        write($msgsock, $talkback, strlen($talkback));
        echo "$buf\n";
    } while (TRUE);
    close($msgsock);
} while (TRUE);
close($sock);
?>

Exemple 2. Exemple avec les sockets : Client TCP/IP

Cet exemple est un client HTTP basique. Il se connecte � une page envoi les ent�tes (requ�te HEAD), affiche le retour, et quitte.

<?php
error_reporting(E_ALL);
echo "<h2>TCP/IP Connection</h2>\n";
/* Demande le port du service WWW. */
$service_port = getservbyname('www', 'tcp');
/* Demande l'IP du serveur de destination. */
$address = gethostbyname('www.php.net');
/* Cr�e la connexion TCP/IP. */
$socket = socket(AF_INET, SOCK_STREAM, 0);
if ($socket < 0) {
    echo "socket() a �chou� : raison : " . strerror($socket) . "\n";
} else {
    "socket() r�ussi: " . strerror($socket) . "\n";
}
echo "Connexion � '$address' on port '$service_port'...";
$result = connect($socket, $address, $service_port);
if ($result < 0) {
    echo "connect()  a �chou� : raison : : ($result) " . strerror($result) . "\n";
} else {
    echo "OK.\n";
}
$in = "HEAD / HTTP/1.0\r\n\r\n";
$out = '';
echo "Envoi des ent�tes HTTP HEAD...";
write($socket, $in, strlen($in));
echo "OK.\n";
echo "Lecture de la r�ponse :\n\n";
while (read($socket, $out, 2048)) {
    echo $out;
}
echo "Fermeture de la socket...";
close($socket);
echo "OK.\n\n";
?>

Table des mati�res
socket_accept -- Accepts a connection on a socket
socket_bind -- Binds a name to a socket
socket_clear_error -- Clears the error on the socket or the last error code
socket_close -- Closes a socket resource
socket_connect -- Initiates a connection on a socket
socket_create_listen -- Opens a socket on port to accept connections
socket_create_pair -- Creates a pair of indistinguishable sockets and stores them in fds.
socket_create -- Create a socket (endpoint for communication)
socket_get_option -- Gets socket options for the socket
socket_getpeername --  Queries the remote side of the given socket which may either result in host/port or in a UNIX filesystem path, dependent on its type.
socket_getsockname --  Queries the local side of the given socket which may either result in host/port or in a UNIX filesystem path, dependent on its type.
socket_iovec_add -- Adds a new vector to the scatter/gather array
socket_iovec_alloc -- ...]) Builds a 'struct iovec' for use with sendmsg, recvmsg, writev, and readv
socket_iovec_delete -- Deletes a vector from an array of vectors
socket_iovec_fetch -- Returns the data held in the iovec specified by iovec_id[iovec_position]
socket_iovec_free -- Frees the iovec specified by iovec_id
socket_iovec_set -- Sets the data held in iovec_id[iovec_position] to new_val
socket_last_error -- Returns the last error on the socket
socket_listen -- Listens for a connection on a socket
socket_read -- Reads a maximum of length bytes from a socket
socket_readv -- Reads from an fd, using the scatter-gather array defined by iovec_id
socket_recv -- Receives data from a connected socket
socket_recvfrom -- Receives data from a socket, connected or not
socket_recvmsg -- Used to receive messages on a socket, whether connection-oriented or not
socket_select -- Runs the select() system call on the given arrays of sockets with a timeout specified by tv_sec and tv_usec
socket_send -- Sends data to a connected socket
socket_sendmsg -- Sends a message to a socket, regardless of whether it is connection-oriented or not
socket_sendto -- Sends a message to a socket, whether it is connected or not
socket_set_nonblock -- Sets nonblocking mode for file descriptor fd
socket_set_option -- Sets socket options for the socket
socket_shutdown -- Shuts down a socket for receiving, sending, or both.
socket_strerror -- Return a string describing a socket error
socket_write -- Write to a socket
socket_writev -- Writes to a file descriptor, fd, using the scatter-gather array defined by iovec_id
User Contributed Notes
Sockets
add a note about notes
[email protected]
05-Jun-2001 04:49

After several hours of working with sockets in an attempt to do UDP broadcasting, I thought a little help was in order for anyone else looking to do something similar, since it uses a number of those "undocumented" functions. Here's how I did it:

<?php
// here is a basic opening of the a socket. AF_INET specifies the internet domain. SOCK_DGRAM
// specifies the Datagram socket type the 0 specifies that I want to use the default protcol (which in this
// case is UDP)
$sock = socket(AF_INET, SOCK_DGRAM, 0);

// if the file handle assigned to socket is less than 0 then opening the socket failed
if($sock < 0)
{
echo "socket() failed, error: " . strerror($sock) . "\n";
}

// here's where I set the socket options, this is essential to allow broadcasting. An earlier comment (as of
// June 4th, 2001) explains what the parameters are. For my purposes (UDP broadcasting) I need to set
// the broadcast option at the socket level to true. In C, this done using SOL_SOCKET as the level param
// (2) and SO_BROADCAST as the type param (3). These may exist in PHP but I couldn't reference them
// so I used the values that referencing these variables in C returns (namely 1 and 6 respectively). This
// function is basically just a wrapper to the C function so check out the C documentation for more info
$opt_ret = setsockopt($sock, 1, 6, TRUE);

// if the return value is less than one, an error occured setting the options
if($opt_ret < 0)
{
echo "setsockopt() failed, error: " . strerror($opt_ret) . "\n";
}

// finally I am ready to broad cast something. The sendto function allows this without any
// connections (essential for broadcasting). So, this function sends the contents of $broadcast_string to the
// general broadcast address (255.255.255.255) on port 4096. The 0 (param 4) specifies no special
// options, you can read about the options with man sendto
$send_ret = sendto($sock, $broadcast_string, strlen($broadcast_string), 0, '255.255.255.255', 4096);

// if the return value is less than 0, an error has occured
if($send_ret < 0)
{
echo "sendto() failed, error: " . strerror($send_ret) . "
\n"; }
// be sure to close your socket when you're done
close($sock);

[email protected]
18-Feb-2002 12:27

Below is a simple forked daemon I wrote in PHP. I haven't seen one yet anywhere else, so I thought some people might be wondering how to do it. Execute
with php -q <file>

<?PHP

/*

PHP forked daemon
Standalone PHP binary must be compiled with --enable-sockets and --enable-pcntl
Dave M. -2002
Online Services USA
*/

function sig_handler($signo) {

switch($signo) {
case SIGTERM:
// handle shutdown tasks
exit;
break;
case SIGHUP:
// handle restart tasks
break;
case SIGUSR1:
print "Caught SIGUSR1...\n";
break;
case SIGCHLD:
while( pcntl_waitpid(-1,$status,WNOHANG)>0 ) {
}
break;
case SIGINT:
exit;
default:
// not implemented yet...
break;
}

}

function interact($sock) {

// Custom code goes here... e.g: socket_read() socket_write()...

}

function become_daemon() {

$child = pcntl_fork();
if($child) {
exit; // kill parent
}
posix_setsid(); // become session leader
chdir("/");
umask(0); // clear umask
return posix_getpid();

}

function open_pid_file($file) {

if(file_exists($file)) {
$fp = fopen($file,"r");
$pid = fgets($fp,1024);
fclose($fp);
if(posix_kill($pid,0)) {
print "Server already running with PID: $pid\n";
exit;
}
print "Removing PID file for defunct server process $pid\n";
if(!unlink($file)) {
print "Cannot unlink PID file $file\n";
exit;
}
}
if($fp = fopen($file,"w")) {
return $fp;
} else {
print "Unable to open PID file $file for writing...\n";
exit;
}
}

function change_identity($uid,$gid) {
global $pid_file;
if(!posix_setgid($gid)) {
print "Unable to setgid to $gid!\n";
unlink($pid_file);
exit;
}
if(!posix_setuid($uid)) {
print "Unable to setuid to $uid!\n";
unlink($pid_file);
exit;
}


}

error_reporting (4);

set_time_limit (0);

ob_implicit_flush ();

$pid_file = '/tmp/php_daemon.pid';

$underpriv_uid = '99'; // uid 99 == user nobody, at least on my system.
$underpriv_gid = '99';

$port = 10000;
$address = 0; // 0 binds to all addresses, may not work on fbsd

$quit = 0;

pcntl_signal(SIGCHLD, "sig_handler");
pcntl_signal(SIGTERM, "sig_handler");
pcntl_signal(SIGINT, "sig_handler");

$fh = open_pid_file($pid_file);

if (($sock = socket_create (AF_INET, SOCK_STREAM, 0)) < 0) {
print "socket_create() failed: reason: " . socket_strerror ($sock) . "\n";
}

if (($ret = socket_bind ($sock, $address, $port)) < 0) {
print "socket_bind() failed: reason: " . socket_strerror ($ret) . "\n";
}

if (($ret = socket_listen ($sock, 0)) < 0) {
print "socket_listen() failed: reason: " . socket_strerror ($ret) . "\n";
}

change_identity($underpriv_uid,$underpriv_gid);

print "Server ready. Waiting for connections.....\n";

$pid = become_daemon();
fputs($fh,$pid);
fclose($fh);

while(!$quit) {

if (($connection = socket_accept($sock)) < 0) {
next;
}

if( ($child = pcntl_fork()) == -1 ) {
print "Could not fork!!\n";
print "Dying...\n";
$quit++;
}
elseif($child == 0) {
socket_close($sock);
interact($connection);
exit;
}

socket_close($connection);

}

if(posix_getpid() == $pid) {
unlink($pid_file);
}

daniel[at]lorch.cc
22-Feb-2002 03:32

"Beej's Guide to Network Programming" is an absolutely excellent and easy to understand tutorial to socket programming. It was written for C developers, but as the socket functions in PHP are (almost) analoguous, this should not be a problem.


daniel[at]lorch.cc
02-Apr-2002 12:31

Although this is not the primary use of PHP, writing a server daemon in PHP is easily feasible.

The most advanced webserver I've seen so far (with an incredible feature-list) is nanoweb:



<advertizing>

I'm trying to do the same thing, but I'm less advanced than nanoweb. My primary goal is to create a "framework" on top other developers should be able to easily create *any* server. Feel free to join the project :)



</advertizing>

Pieter
09-Apr-2002 08:03

On Windows it's also possible to use sockets

Just open your PHP.ini and look for the following part:

;extension=extensions\php_sockets.dll

Unmark it like this

extension=extensions\php_sockets.dll

and there's Sockets to be build in your programs

[email protected]
16-Jun-2002 01:08

Great, that warning about versions. No I use 4.1.2 and can only use the function socket_clear_error (PHP 4 >= 4.2.0). The rest is 4.1.0. I'm impressed!
Billy

[email protected]
08-Jul-2002 10:03

To Ramar: All you have to do is to use fopen() function.

Here is an example of using POST method:
$host = "www.php.net";
$data = "lang=en_US&pattern=sockets&show=quickref";

$fp = fsockopen($host,80);

fputs($fp, "POST /search.php HTTP/1.1\n");
fputs($fp, "Host: $host\n");
fputs($fp, "Content-type: application/x-www-form-urlencoded\n");
fputs($fp, "Content-length: " . strlen($data) . "\n");
fputs($fp, "User-Agent: MSIE\n");
fputs($fp, "Connection: close\n\n");
fputs($fp, $data);

while (!feof($fp))
$buf .= fgets($fp,128);
fclose($fp);

echo $buf;

saryon at unfix dot org
09-Jul-2002 03:42

I found this EXTREMELY useful link on the zend php
mailing list:



It's about being able to use multiple connections
in a php socket server, WITHOUT having
to use those threads everyone seems to be
so very fond of.
works very well :)
(ps: i didn't make it, so....don't say thanks to me ;),
thank him)

add a note about notes
previoussnmpwalkoidsocket_acceptnext
Last updated: Tue, 09 Jul 2002
show source | credits | stats | mirror sites
Copyright © 2001, 2002 The PHP Group
All rights reserved.
This mirror generously provided by:
Last updated: Sat Aug 31 06:19:44 2002 CEST