Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
<?php declare(strict_types = 1);
$server = stream_socket_server("tcp://");
$serverId = (int)$server;
$readSockets = [$serverId => $server];
$writeSockets = $pendingWriteData = [];
while (true) {
// do anything you might need to do at the beginning of each loop tick
$r = $readSockets; // create copies of all watchable socket arrays
$w = $writeSockets;
$e = null; // we still don't care about OOB data. Very few applications do.
// how long (max) select() will block waiting for something to happen
$timeoutSecs = 1;
$timeoutUSecs = 0;
$selectResult = stream_select($r, $w, $e, $timeoutSecs, $timeoutUSecs);
if ($selectResult === false) {
// an E_WARNING is raised in this case, check that to find out if there's any more info about what went wrong
echo "select() returned an error\n";
if ($selectResult > 0) {
// if something has happened on a socket then process it
echo count($r) . " sockets have readable activity\n";
foreach ($r as $socket) {
$socketId = (int)$socket;
if ($socketId === $serverId) {
$client = stream_socket_accept($server);
stream_set_blocking($client, false); // set the stream to non-blocking as soon as it's created
$clientId = (int)$client;
$readSockets[$clientId] = $client;
echo "Got a new client #{$clientId}\n";
} else {
$data = fread($socket, 1024);
if ($data === '') {
echo "Client #{$socketId} disconnected\n";
echo "Got data from client #{$socketId}: {$data}\n";
$pendingWriteData[$socketId] = $data;
$writeSockets[$socketId] = $socket; // this is a simple example so we won't actually try to send the
// data here so that we can force the loop to detect writable
// sockets. In the real world, we'd actually try and send the data
// immediately and only queue it in the buffer if we couldn't send
// it all.
echo "Responding with $data\n";
echo count($w) . " sockets are writable\n";
foreach ($w as $socket) {
$socketId = (int)$socket;
$data = $pendingWriteData[$socketId];
$dataLen = strlen($data);
echo "Sending data {$data} ({$dataLen} bytes) to client #{$socketId}\n";
$sent = fwrite($socket, $data);
if ($sent === false) {
echo "Sending data failed!\n"; // E_WARNING should tell you want happened here
unset($pendingWriteData[$socketId], $writeSockets[$socketId]);
echo "Sent {$sent} bytes to client #{$socketId}\n";
if ($sent === $dataLen) {
echo "Send buffer for client #{$socketId} drained\n";
unset($pendingWriteData[$socketId], $writeSockets[$socketId]);
// if we get here, it means that we only managed to send part of the data. This won't happen unless you are
// trying to send a lot of data (probably several KB) in one go. So here we just remove the data that we sent
// from the start of our buffer, and leave the socket to be watched for writes so we can try again.
$pendingWriteData[$socketId] = substr($pendingWriteData[$socketId], $sent);
// do anything you might need to do at the end of each loop tick
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment