I've spent quite a few hours around this to learn a few tips and tricks:
- Don't use PHP's socket_read() - allthough with PHP_BINARY_READ you *CAN* solve a lot of your problems, but not all of them. I noticed that eventually the client socket "jamms" because the buffer doesn't clear, so you get stuck with a socket that you can only write to, but when you try to read from this socket, nothing returns. A very good alternative is socket_recv()
- OOP (Object Oriented Programming) is a good thing, it makes upgrades and fixes easy to do, so at least you would need two classes, one for the server and one for a user. Each user is an object.
- When reading from a socket, concatenated commands may occur, use a special delimiter (char(0) works) to split them.
- Use nonblocking sockets, you don't want your server to freeze everytime a client socket writes.
- "Ping" your clients, sometimes the kill signal gets lost, the server thinks the socket is still active and unitl you write to that socket, there is no way of knowing if the connection is still established or not. Disconnect the socket on read or write error and that way your sockets will be purged automatically.
Here's a
rough framework of what I'm talking about (may be updated some time soon):
class user {
var $socket;
function user($socket) {
$this->socket=$socket;
}
}
class server {
var $socket;
var $working;
var $clients;
//constructor
function server($port) {
$this->socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
socket_set_option($this->socket,SOL_SOCKET,SO_REUSEADDR,1);
socket_bind($this->socket,0,$port);
socket_listen($this->socket);
socket_set_nonblock($this->socket);
$this->working = true; //if all else fails, this does too!
array_push($this->clients($this->socket));
}
function me($sock) {
//if the socket is the server socket
return $this->socket == $sock;
}
//read from the buffer
function read(&$sock,$i,$len=2048,$flag=0) {
$recv_data = @socket_recv($sock,$jammeddata,$len,$flag);
if ($recv_data == 0) {
//error on read or client quitted
$this->remove_client($sock);
} else {
//reading from socket
$jammed = explode(chr(0), $jammeddata); //is it jammed?
if (count($jammed) > 2) {
//socket is jammed, parse it
foreach($jammed as $unjammed) {
$this->on_read($unjammed,$i);
}
return true;
}
//clean read
return $this->on_read($jammeddata,$i);
}
return false;
}
//event handler - PUT ALL YOUR FUNCTIONS HERE
function on_read() {
}
}
$server = new $server(10000);
while($server->working) {
//put all current clients in the array
$clients = $server->clients;
//put all sockets that are trying to wrote in the array
socket_select($clients,$write=NULL,$except=NULL,0);
//loop through the generated array of clients
foreach($clients as $client) {
if($server->me($client)) {
//accept incoming connections
array_push(new user(socket_accept($client)));
}
//read from the socket that is trying to write
$server->read($client);
}
}