i have written a socket server to talk to multiple action game clients simultaneously. i based my code on a chat server that someone was kind enough to give me.
the problem i seem to be having is that messages which i want sent out to sockets immediately seem to get stuck in a buffer. i know that i'm not supposed to expect to write an entire message to a socket...but i am not sure how to make my server promptly send out all messages. i think the issue is partly the multitasking thing...the script, while trying to write to a socket, gets interrupted to handle another incoming packet and then never gets around to finishing the socket_write. this multitasking thing is killing me! can anyone recommend how i should change my code...or perhaps a good resource for socket servers?
Also, i want to use UDP instead of TCP but i have no experience writing protocols to make sure packets get through. obviously action games need to be quick. any advice here would be welcome as well.
i have included most of my socket server script below...i left out some functions which didn't seem critical to this problem.
<?
$listen_addr = '0.0.0.0';
$listen_port = 1234;
/* this is to be a daemon, don't want to auto-timeout and no error messages! */
set_time_limit(0);
error_reporting(0);
/* display error message */
function myerror() {
echo '[error]: ' . socket_strerror(socket_last_error()) . "\n";
}
/* display error message and die */
function myerror_d() {
myerror();
die();
}
/* send a message to a socket --client expects \\0 to terminate all mesgs.*/
function send_single($sock, $message) {
socket_write($sock, "$message\\0");
}
/* handle incoming data */
function handle_data($sock, $read) {
global $cdata;
// if the buffer isn't empty
if ($cdata[$sock]['buf'] != '')
// set $read to whatever's left in the buffer followed by $read
$read = $cdata[$sock]['buf'] . $read;
// get rid of any \r chars in $read
$read = str_replace("\r", '', $read);
//set the buffer to everything following the last \\0 (but not including \\0)
$cdata[$sock]['buf'] = substr(strrchr($read, "\\0"), 1);
// set $read to everything leading up to the \\0
$read = substr($read, 0, strpos($read, "\\0"));
handle_it($sock, $read);
}
/* handle waiting players requests text */
function handle_it($sock, $data) {
global $cdata;
// code here to determine where the data goes...
// $intOutSock = blah blah
send_single($intOutSock, $data);
}
/* assign listening socket */
if (!($s_listen = socket_create(AF_INET, SOCK_STREAM, 0)))
myerror_d();
/* reuse listening socket address */
if (!socket_set_option($s_listen, SOL_SOCKET, SO_REUSEADDR, 1))
myerror_d();
/* set socket to non-blocking */
if (!socket_set_nonblock($s_listen))
myerror_d();
/* bind listening socket to specific address/port */
if (!socket_bind($s_listen, $listen_addr, $listen_port))
myerror_d();
/* listen on listening socket */
if (!socket_listen($s_listen))
myerror_d();
/* set initial vars and loop until $abort is set to true */
$s_clients = Array();
$abort = false;
while (!$abort) {
/* sockets we want to pay attention to */
$set = array_merge($s_listen, $s_clients);
if (socket_select($set, $set_w = NULL, $set_e = NULL, 1, 0) > 0) {
/* loop through sockets */
foreach ($set as $sock) {
/* listening socket has a connection, deal with it */
if ($sock == $s_listen) {
if (!($this = socket_accept($s_listen)))
myerror();
else {
/* add socket to client list and announce connection */
$s_clients[$this] = $this;
socket_getpeername($this, $addr);
$cdata[$this]['addr'] = $addr;
$cdata[$this]['buf'] = '';
$cdata[$this]['state'] = STATE_NICKNAME;
echo "[connection]: $addr\n";
// prompt client for identifier...
send_single($this, 'N');
}
}
else {
/* client socket has incoming data */
if (($read = socket_read($sock, 1024)) === false || $read == '') {
if ($read != '')
myerror();
else /* no error, but connection was closed, so tell everyone */
on_quit($sock);
/* remove client from arrays */
unset($s_clients[$sock]);
unset($cdata[$sock]);
list_waiting();
}
else {
/* fa data with a null char */
if (strchr($read, "\\0") === false)
$cdata[$sock]['buf'] .= $read;
else
handle_data($sock, $read);
}
}
}
}
}
echo "[end]\n";
?>