PHP
Sockets
Ricerca…
Socket client TCP
Creazione di un socket che utilizza TCP (Transmission Control Protocol)
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
Assicurarsi che il socket sia stato creato correttamente. La funzione onSocketFailure
deriva da Gestione errori di socket in questo argomento.
if(!is_resource($socket)) onSocketFailure("Failed to create socket");
Collegare il socket a un indirizzo specificato
La seconda riga fallisce con garbo se la connessione fallisce.
socket_connect($socket, "chat.stackoverflow.com", 6667)
or onSocketFailure("Failed to connect to chat.stackoverflow.com:6667", $socket);
Invio di dati al server
La funzione socket_write
invia byte attraverso un socket. In PHP, una matrice di byte è rappresentata da una stringa, che normalmente non è sensibile alla codifica.
socket_write($socket, "NICK Alice\r\nUSER alice 0 * :Alice\r\n");
Ricezione di dati dal server
Lo snippet seguente riceve alcuni dati dal server utilizzando la funzione socket_read
.
Passando a PHP_NORMAL_READ
come il terzo parametro si legge fino a un byte \r
/ \n
e questo byte è incluso nel valore restituito.
Passando PHP_BINARY_READ
, al contrario, legge la quantità richiesta di dati dallo stream.
Se socket_set_nonblock
stato chiamato in precedenza e PHP_BINARY_READ
viene utilizzato, socket_read
restituirà false
immediatamente. In caso contrario, il metodo blocca fino a quando non vengono ricevuti dati sufficienti (per raggiungere la lunghezza nel secondo parametro o per raggiungere una fine riga) o il socket è chiuso.
Questo esempio legge i dati da un presunto server IRC.
while(true) {
// read a line from the socket
$line = socket_read($socket, 1024, PHP_NORMAL_READ);
if(substr($line, -1) === "\r") {
// read/skip one byte from the socket
// we assume that the next byte in the stream must be a \n.
// this is actually bad in practice; the script is vulnerable to unexpected values
socket_read($socket, 1, PHP_BINARY_READ);
}
$message = parseLine($line);
if($message->type === "QUIT") break;
}
Chiudere la presa
La chiusura del socket libera il socket e le sue risorse associate.
socket_close($socket);
Socket del server TCP
Creazione di prese
Creare un socket che utilizza il TCP. È come creare un socket client.
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
Attacco presa
Collega le connessioni da una data rete (parametro 2) per una porta specifica (parametro 3) alla presa.
Il secondo parametro è solitamente "0.0.0.0"
, che accetta la connessione da tutte le reti. Io posso anche
Una causa comune di errori da socket_bind
è che l'indirizzo specificato è già associato a un altro processo . Di solito, altri processi vengono uccisi (di solito manualmente per evitare di uccidere accidentalmente processi critici) in modo che i socket vengano liberati.
socket_bind($socket, "0.0.0.0", 6667) or onSocketFailure("Failed to bind to 0.0.0.0:6667");
Imposta un socket per l'ascolto
Fai in modo che il socket ascolti le connessioni in entrata usando socket_listen
. Il secondo parametro è il numero massimo di connessioni per consentire l'accodamento prima che vengano accettate.
socket_listen($socket, 5);
Gestione della connessione
Un server TCP è in realtà un server che gestisce le connessioni figlio. socket_accept
crea una nuova connessione figlio.
$conn = socket_accept($socket);
Il trasferimento dati per una connessione da socket_accept
è uguale a quello per un socket client TCP .
Quando questa connessione deve essere chiusa, chiama socket_close($conn);
direttamente. Ciò non influirà sul socket del server TCP originale.
Chiusura del server
D'altra parte, socket_close($socket);
dovrebbe essere chiamato quando il server non è più utilizzato. Ciò libererà anche l'indirizzo TCP, consentendo ad altri processi di collegarsi all'indirizzo.
Gestione degli errori di socket
socket_last_error
può essere utilizzato per ottenere l'ID errore dell'ultimo errore dall'estensione socket.
socket_strerror
può essere utilizzato per convertire l'ID in stringhe leggibili dall'uomo.
function onSocketFailure(string $message, $socket = null) {
if(is_resource($socket)) {
$message .= ": " . socket_strerror(socket_last_error($socket));
}
die($message);
}
Socket del server UDP
Un server UDP (user datagram protocol), a differenza di TCP, non è basato sul flusso. È basato su pacchetti, ovvero un client invia i dati in unità denominate "pacchetti" al server e il client identifica i client in base al loro indirizzo. Non esiste una funzione incorporata che colleghi diversi pacchetti inviati dallo stesso client (diversamente dal TCP, dove i dati dallo stesso client sono gestiti da una risorsa specifica creata da socket_accept
). Può essere pensato come una nuova connessione TCP è accettata e chiusa ogni volta che arriva un pacchetto UDP.
Creazione di un socket del server UDP
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
Associazione di un socket a un indirizzo
I parametri sono gli stessi di un server TCP.
socket_bind($socket, "0.0.0.0", 9000) or onSocketFailure("Failed to bind to 0.0.0.0:9000", $socket);
Invio di un pacchetto
Questa riga invia $data
in un pacchetto UDP a $address
: $port
.
socket_sendto($socket, $data, strlen($data), 0, $address, $port);
Ricevere un pacchetto
Lo snippet seguente tenta di gestire i pacchetti UDP in modo indicizzato dal client.
$clients = [];
while (true){
socket_recvfrom($socket, $buffer, 32768, 0, $ip, $port) === true
or onSocketFailure("Failed to receive packet", $socket);
$address = "$ip:$port";
if (!isset($clients[$address])) $clients[$address] = new Client();
$clients[$address]->handlePacket($buffer);
}
Chiusura del server
socket_close
può essere utilizzato sulla risorsa socket del server UDP. Questo libererà l'indirizzo UDP, consentendo ad altri processi di collegarsi a questo indirizzo.