-
-
Save DaveRandom/e5a17a805d85ec2b7d07d29b1fd8e1c2 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); | |
function send_data($socket, $data) | |
{ | |
echo "Sending data {$data}\n"; | |
fwrite($socket, $data); | |
$response = fread($socket, 1024); | |
echo "Got response: {$response}\n"; | |
} | |
$socket = stream_socket_client("tcp://127.0.0.1:47806"); | |
send_data($socket, 'HELLO'); | |
send_data($socket, 'WHAT YOU UP TO?'); | |
send_data($socket, 'HAVING FUN?'); |
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 = []; | |
// This defines our "protocol". It's just an array that maps "request" strings to "response" strings | |
$protocolDefinition = [ | |
'HELLO' => 'HEY THERE', | |
'WHAT YOU UP TO?' => 'OH NOT MUCH', | |
'HAVING FUN?' => 'YEH THIS IS GREAT!', | |
]; | |
$badRequestResponse = "SORRY I DIDN'T UNDERSTAND YOU :-("; // send this back to any data we don't recognise | |
while (true) { | |
// do anything you might need to do at the beginning of each loop tick | |
echo "Loop tick\n"; | |
$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] = $protocolDefinition[$data] ?? $badRequestResponse; | |
$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 {$pendingWriteData[$socketId]}\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