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;
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;
array_push($this->clients($this->socket));
}
function me($sock) {
return $this->socket == $sock;
}
function read(&$sock,$i,$len=2048,$flag=0) {
$recv_data = @socket_recv($sock,$jammeddata,$len,$flag);
if ($recv_data == 0) {
$this->remove_client($sock);
} else {
$jammed = explode(chr(0), $jammeddata);
if (count($jammed) > 2) {
foreach($jammed as $unjammed) {
$this->on_read($unjammed,$i);
}
return true;
}
return $this->on_read($jammeddata,$i);
}
return false;
}
function on_read() {
}
}
$server = new $server(10000);
while($server->working) {
$clients = $server->clients;
socket_select($clients,$write=NULL,$except=NULL,0);
foreach($clients as $client) {
if($server->me($client)) {
array_push(new user(socket_accept($client)));
}
$server->read($client);
}
}