<?php
/*
socket server example where the socket server can take console as well as remote commands.
This example is a chat server. 2 instances of the chat plugins are started. One on port 5000 and one on port 5001.
Scroll down to ## EXAMPLE: ## to modify this example
Use your telnet client to connect to the server.
Use 'telnet localhost 5000' to connect to first chat server or 'telnet localhost 5001' to connect to second chat server
You can also interact with the main console by typing commands in the main console.
example:
## EXAMPLE TO RUN TWO SEPERATE CHAT SERVERS IN THE SAME PROGRAM (CAN ALSO INTERACT WITH MAIN CLI SERVER): ##
// create plugins
$host = '127.0.0.1';
$port = 5001;
$plugin_a = new my_plugin($host, $port);
// create another different chat server on a different port and run at same time
$host = '127.0.0.1';
$port = 5000;
$plugin_b = new my_plugin($host, $port);
// create main object that controls the plugins
$cli = new nb_cli();
// add plugins to main controller
$cli->add_plugin($plugin_a);
$cli->add_plugin($plugin_b);
// run our main controller which will run the plugins welcome() functions
$cli->welcome();
// run our main controller which will run the plugins run() functions in a loop
// maximum speed is set in main controller, but each plugin can time their own runs
$cli->run();
*/
include_once('class.nb_cli_1.0.php');
class my_plugin extends nb_plugin {
private $stdin;
private $stdout;
private $socket;
private $clients = [];
private $data;
public function set($key, $value) {
$this->data[$key] = $value;
}
public function get($key) {
if (isset($this->data[$key]) )
return $this->data[$key];
}
public function __construct($host='127.0.0.1', $port=8080) {
stream_set_blocking(STDOUT, false);
stream_set_blocking(STDIN, false);
$this->stdin = fopen('php://stdin', 'r');
$this->stdout = fopen('php://stdout', 'w');
$this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_nonblock($this->socket);
socket_bind($this->socket, $host, $port);
socket_listen($this->socket);
}
public function out($msg) {
fwrite($this->stdout, $msg);
}
public function handleCommand($command) {
// runs on local console
// process commands from user when they send data
// first lets find params
$command = trim($command);
$command = explode(' ', $command, 2);
$params = '';
if(isset($command[1]))
$params = trim($command[1]);
$command = $command[0];
switch ($command) {
case 'test':
$help = "Test command\n";
// $this->out($help, $client);
$this->out($help);
break;
case 'help':case 'h':case '?':
$help = "---\r\n";
$help .= "This program demonstrates using sockets with a non blocking cli local interface.\r\n";
$help .= "You are currently viewing the local help on the server side.\r\n\n";
$help .= "Available commands:\r\n";
$help .= " test - Test command\r\n";
$help .= " quit - Quit the program\r\n";
$help .= "---\n\n";
$this->out($help);
// $this->out($help, $client);
break;
case 'users':
$user_count = count($this->clients);
$str = "There are currently $user_count users connected.\r\n";
$this->out($str);
break;
case 'msg':
$this->sockets_out("\r\nserver msg :: " . $params ." ::\r\n");
break;
}
}
public function welcome()
{
$welcome = "\n\n";
$welcome .= "-- NonBlockingCLI test server (local console type ? for help) --\n";
$welcome .= "\n\n\n";
$this->out($welcome); // local out
}
## BEGIN :: REMOTE CLIENTS ##
public function socket_prompt($client)
{
// triggered by main loop when code requests a prompt
$this->socket_out("\r\n > ", $client);
}
public function socket_welcome($client) {
// triggered by main loop when code requests a welcome
$welcome = "-- NonBlockingCLI test server --\r\n";
$welcome .= "Welcome to the NonBlockingCLI test server.\r\n";
$welcome .= "Type 'h' or 'help' for a list of commands.\r\n";
$welcome .= "Type 'quit' to exit.\r\n";
$welcome .= "\r\n\n";
$this->socket_out($welcome, $client);
}
public function socket_check_for_new()
{
// Check for new client connections
$client = socket_accept($this->socket);
if ($client !== false) {
// A new client has connected
$this->clients[] = $client;
$client_key = array_search($client, $this->clients);
$this->set($client_key, array(
'uid' => uniqid(),
'tstamp_connected' => time(),
'buf' => ''
));
$this->socket_welcome($client);
}
}
public function socket_disconnect($client)
{
// disconnected client
$this->out("Client disconnected.\n");
// remove data for client
$client_key = array_search($client, $this->clients);
unset($this->data[$client_key]);
// now remove client
$key = array_search($client, $this->clients);
unset($this->clients[$key]);
socket_close($client);
}
public function sockets_read()
{
// Handle incoming client data
foreach ($this->clients as $client) {
$input = socket_read($client, 1024);
if($input !== false)
{
if($input == '')
{
$this->socket_disconnect($client);
continue;
}
// $hex = bin2hex($input);
// echo "{".$input."::".$hex."}";
// if input is a \n then we have a command else add to buffer
$client_key = array_search($client, $this->clients);
// if we don't have a client, skip next part...
if ($client_key === false)
continue;
$this->data[$client_key]['buf'] .= $input;
// if \n on end of buffer then we have a command
if (substr( $this->data[$client_key]['buf'] , -1) == "\n") {
$command = trim($this->data[$client_key]['buf']);
$this->socket_command($command, $client);
$this->data[$client_key]['buf'] = '';
}
}
}
} // end sockets_read
public function socket_command($command, $client)
{
$client_key = array_search($client, $this->clients);
// first lets find params
$command = trim($command);
$command = explode(' ', $command, 2);
$params = '';
if(isset($command[1]))
$params = trim($command[1]);
$command = $command[0];
$this->out("Client $client_key sent command: $command with params: $params\n");
$this->socket_out("Handling command:".$command."\r\n", $client);
switch ($command) {
case 'test':
$help = "Test command\r\n";
$this->socket_out($help, $client);
break;
case 'help':case 'h':case '?':
$help = "---\r\n";
$help .= "This program demonstrates using sockets with a non blocking cli local interface.\r\n";
$help .= "You are currently viewing the remote help on the client side.\r\n\n";
$help .= "Available commands:\r\n";
$help .= " test - Test command\r\n";
$help .= " quit - Quit the program\r\n";
$help .= " users - Show how many users are connected\r\n";
$help .= " say - Send a message to all users eg) say hi\r\n";
$help .= "---\r\n\n";
$this->socket_out($help, $client);
$this->socket_prompt($client);
break;
case 'users':
$user_count = count($this->clients);
$str = "There are currently $user_count users connected.\r\n";
$this->socket_out($str, $client);
break;
case 'say':
$this->out("client ".$client_key." says :: " . $params ." ::\n"); // server
$this->socket_out("You say: " . $params . "\r\n", $client); // client
$this->sockets_out_other("\r\nclient ".$client_key." says :: " . $params ." ::\r\n", $client); // other clients
$this->socket_prompt($client);
break;
case 'quit':
$this->socket_out("Goodbye.\r\n", $client);
$this->socket_out("quit\r\n", $client);
$this->socket_disconnect($client);
break;
}
}
public function socket_out($msg, $client = null) {
socket_write($client, $msg, strlen($msg));
}
public function sockets_out($msg)
{
foreach ($this->clients as $client) {
$this->socket_out($msg, $client);
}
}
public function sockets_out_other($msg, $client)
{
foreach ($this->clients as $other_client) {
if($other_client !== $client)
{
$this->socket_out($msg, $other_client);
$this->socket_prompt($other_client);
}
}
}
## END :: REMOTE CLIENTS ##
public function run() {
// this loop runs at main class speed
$this->run_loop_1(); // output current time every second
// .. can add other loops. Use run_loop_1 as an example.
}
public function run_loop_1() {
// check our sockets // running at full server loop speed
$this->socket_check_for_new();
$this->sockets_read();
}
}
## EXAMPLE: ##
// create plugins
$host = '127.0.0.1';
$port = 5001;
$plugin_a = new my_plugin($host, $port);
// create another different chat server on a different port and run at same time
$host = '127.0.0.1';
$port = 5000;
$plugin_b = new my_plugin($host, $port);
// create main object that controls the plugins
$cli = new nb_cli();
// add plugins to main controller
$cli->add_plugin($plugin_a);
$cli->add_plugin($plugin_b);
// run our main controller which will run the plugins welcome() functions
$cli->welcome();
// run our main controller which will run the plugins run() functions in a loop
// maximum speed is set in main controller, but each plugin can time their own runs
$cli->run();
?>
|