Last active
September 22, 2016 10:04
-
-
Save ikariiin/0ac9da46cb3051532e74f223b831dc64 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php declare(strict_types = 1); | |
$server = stream_socket_server("tcp://127.0.0.1:47806"); | |
$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"; | |
break; | |
} | |
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 === '') { | |
unset($readSockets[$socketId]); | |
echo "Client #{$socketId} disconnected\n"; | |
continue; | |
} | |
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]); | |
continue; | |
} | |
echo "Sent {$sent} bytes to client #{$socketId}\n"; | |
if ($sent === $dataLen) { | |
echo "Send buffer for client #{$socketId} drained\n"; | |
unset($pendingWriteData[$socketId], $writeSockets[$socketId]); | |
continue; | |
} | |
// 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