php xml socket server problem
Posted: Sun Nov 06, 2005 2:33 am
ok .. I am attaching our xml socket server written in PHP at the end of description. This PHP runs on Linux as standalone server in NON-BLOCKING mode because of the flash. Card game is developed in Flash.
Here is short description what we expect from this server and where the problem is.
Server runs perfect on low number of the logged players but for some reason with more players (100 or more) error we get from the Linux system is "Resource temporarily unavailable" ... it is basically not a fatal error because this means system buffer is full and this data will be processed in next run of the script ... well .. not in our case.
Our game has always 4 players and we created server to sends data only to those 4 players when they start a game.
Problem:
Lets say I drop the card. Flash game is not sending this card immediately on the table and flash is waiting to receive the same command I sent to other 3 players. When I receive a command, Flash is droping a card.
Here is the best part. Considering that this is TCP/IP protocol. We assumed that this command MUST reach all 4 players no matter of the bandwidth user has, but for some reason (maybe because of the Linux error "Resource temporarily unavailable") our PHP xml server sends data only to some of them .. in most cases it does not sends data only to 1 player which means 3 of them receive command.
We tried to solve this by buffering last command on the PHP server and to send data repeatedly couple of times assuming that it will finally send command to all users. Please note that this repeating does not affect players that already got command in first attempt.
Still, we have cases where command is never sent from PHP and never reach 1 of 4 players and this happens no matter what kind of connection user has or OS he is running.
If you have any idea I would appreciate your urgent help because we must have full and functional server in place in few days.
Thank you in advance.
// code
<?php
setlocale(LC_ALL, 'hr_HR');
set_time_limit(0);
error_reporting(0);
define('MAXLINE', 4000);
define('LISTENQ', 10);
define('PORT', 9105);
define('FD_SETSIZE', 500);
ini_set('SMTP','mail.htnet.hr');
ini_set('sendmail_from' ,'me@mymail.com');
ini_set ('track_errors', 1);
$elapsed="";
$strel="%3E%3E";
function userErrorHandler ($errno, $errmsg, $filename, $linenum, $vars)
{
$dt = date("Y-m-d H:i:s (T)");
$errortype = array (
1 => "Error",
2 => "Warning",
4 => "Parsing Error",
8 => "Notice",
16 => "Core Error",
32 => "Core Warning",
64 => "Compile Error",
128 => "Compile Warning",
256 => "User Error",
512 => "User Warning",
1024=> "User Notice"
);
$user_errors = array(E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE);
if (($errno!=2) && ($errno!=8)) {
$err= "*** Socket Server ".PORT." ****************************\n";
$err .= " Error number : $errno\n";
$err .= " Error type: $errortype[$errno]\n";
$err .= " Error description : $php_errormsg\n";
$err .= "Code line : $linenum\n";
print $err;
mail("design@green-vector.hr","SS Error",$err);
}
}
function flush_buffer($x) {
global $client;
$len=strpos($client[$x][7],"\0")+1;
$sent=socket_write($client[$x][0],$client[$x][7]);
if ($sent===false) {
$client[$x][9]=2;
return;
}
else {
if ($client[$x][9]>0) $client[$x][9]--;
if (($sent>0) && ($sent<=$len) && ($client[$x][9]==0)) $client[$x][7]=substr($client[$x][7],$sent);
}
}
function process_message($i) {
global $client,$strel,$wfds;
$p=strpos($client[$i][6],"\0");
if ($p!==false) {
$n=substr($client[$i][6],0,$p);
$client[$i][6]=substr($client[$i][6],$p+1);
//new client login (this portion sends data to all users)
if ($client[$i][1]==null) {
$client[$i][1]=$n;
for ($j = 0; $j < count($client); $j++) {
if (($client[$j][0]<>$client[$i][0])) {
$client[$i][7].="$j$strel".$client[$j][1]."$strel".$client[$j][3]."\0";
if (in_array($client[$j][0], $wfds)) flush_buffer($i);
}
if (!$client[$j][8]) {
$client[$j][7].="$i$strel".$client[$i][1]."$strel".$client[$i][3]."\0";
if (in_array($client[$j][0], $wfds)) flush_buffer($j);
}
}
return(true);
}
//status change of the player (in the game or on the list)
$sp=split($strel,$n);
if ($sp[0] == 'kraj') {
for ($j = 0; $j < count($client); $j++) {
if ($client[$i][2]==$client[$j][2]) $client[$j][8]=false;
}
return(true);
}
elseif ($sp[0] == 'status') {
$xpl=explode('%7C',$sp[1]);
if (($xpl[0]=='ztv') || ($xpl[0]=='otv') || ($xpl[0]=='igr')) {
if ($xpl[0]=='igr') {
for ($j=0;$j<count($client);$j++) {
if ($client[$i][2]==$client[$j][2]) $client[$j][8]=true;
}
}
$ime=explode($strel,$client[$i][1]);
$client[$i][2]=$ime[1];
$client[$i][3]=$sp[1];
}
else {
if ($client[$i][2]!=$xpl[0]) {
$igraca=0;
for ($j=0;$j<count($client);$j++) {
if ($xpl[0]==$client[$j][2]) $igraca++;
}
if ($igraca>3) return(true);
}
$client[$i][2]=$xpl[0];
$client[$i][3]=$sp[1];
}
}
//this portion sends data only to the users in game room (4 users always)
$chk=0;
for ($j = 0; $j < count($client); $j++) {
if (($client[$i][2]==$client[$j][2]) || ((!$client[$j][8]) && (($sp[0]=='status')||($sp[0]=='call'))) ) {
$client[$j][7].="$i$strel$n\0";
if (in_array($client[$j][0], $wfds)) flush_buffer($j);
$chk++;
}
}
if (($chk!=4) && ($client[$i][8])) print "W:paket od: $i -u grupi: ".$client[$i][2]." -poslan na: $chk soketa\n";
}
}
// *** beginning ***
$old_error_handler = set_error_handler("userErrorHandler");
$listenfd = socket_create(AF_INET, SOCK_STREAM, 0);
if ($listenfd) {
print " ___ SERVER START ___P:9105__________________ \n";
print "| Card game |\n";
print "| WELCOME! |\n";
print "| Playtoy Super Sock Router XVI |\n";
print "| (c)2004-2005 Green-Vector |\n";
print "|____________________________________________|\n";
}
else {
die("SS Error - Socket died!\n");
}
socket_setopt($listenfd, SOL_SOCKET, SO_REUSEADDR, 1);
if (!socket_bind($listenfd, "0.0.0.0", PORT)) {
socket_close($listenfd);
die("SS Error - Couldn't bind!\n");
}
socket_listen($listenfd, LISTENQ);
socket_set_nonblock($listenfd);
/*
Clients (field with data)
0 socket
1 login
2 room
3 status
4 remote host
5 remote port
6 input buffer
7 output buffer
8 flag if user is in started game
9 counter
*/
$client=array();
while(1) {
unset($rfds,$wfds);
$rfds[0] = $listenfd;
for ($i = 0;$i<count($client);$i++) {
$rfds[$i+1]=$client[$i][0];
$wfds[$i]=$client[$i][0];
}
socket_select($rfds, $wfds, $null, null);
if (in_array($listenfd, $rfds)) {
$i=array_push($client,array(socket_accept($listenfd),null,null,'free',null,null,'','',false,0))-1;
socket_setopt($client[$i][0], SOL_SOCKET, SO_REUSEADDR, 1);
socket_set_nonblock($client[$i][0]);
socket_getpeername($client[$i][0], $client[$i][4], $client[$i][5]);
$client[$i][7].=(count($client)-1)."$strel"."Joined$strel".$client[$i][4]."\0";
flush_buffer($i);
if ($i >= FD_SETSIZE) {
trigger_error("Too many clients", E_USER_ERROR);
exit;
}
}
// check the buffer of the clients
for ($i = 0; $i < count($client); $i++) {
if ($client[$i][7]!='') {
flush_buffer($i);
}
if ($client[$i][6]!='') {
process_message($i);
}
}
// check clients /if there are any input data)
for ($i = 0; $i < count($client); $i++) {
if (in_array($client[$i][0], $rfds)) {
$rcv=socket_read($client[$i][0], MAXLINE);
if (!$rcv) {
// close client
for ($j = 0; $j <count($client); $j++) {
if ($client[$i][1]!=null) {
if (($client[$j][2]==$client[$i][2]) || (!$client[$j][8])) {
$client[$j][7].="$i$strel"."gone$strel".$client[$i][1]."\0";
flush_buffer($j);
}
}
}
socket_close($client[$i][0]);
array_splice($client,$i,1);
continue;
}
// buffer (collect whole block)
$client[$i][6].=$rcv;
if (process_message($i)) continue;
}
}
}
?>
Here is short description what we expect from this server and where the problem is.
Server runs perfect on low number of the logged players but for some reason with more players (100 or more) error we get from the Linux system is "Resource temporarily unavailable" ... it is basically not a fatal error because this means system buffer is full and this data will be processed in next run of the script ... well .. not in our case.
Our game has always 4 players and we created server to sends data only to those 4 players when they start a game.
Problem:
Lets say I drop the card. Flash game is not sending this card immediately on the table and flash is waiting to receive the same command I sent to other 3 players. When I receive a command, Flash is droping a card.
Here is the best part. Considering that this is TCP/IP protocol. We assumed that this command MUST reach all 4 players no matter of the bandwidth user has, but for some reason (maybe because of the Linux error "Resource temporarily unavailable") our PHP xml server sends data only to some of them .. in most cases it does not sends data only to 1 player which means 3 of them receive command.
We tried to solve this by buffering last command on the PHP server and to send data repeatedly couple of times assuming that it will finally send command to all users. Please note that this repeating does not affect players that already got command in first attempt.
Still, we have cases where command is never sent from PHP and never reach 1 of 4 players and this happens no matter what kind of connection user has or OS he is running.
If you have any idea I would appreciate your urgent help because we must have full and functional server in place in few days.
Thank you in advance.
// code
<?php
setlocale(LC_ALL, 'hr_HR');
set_time_limit(0);
error_reporting(0);
define('MAXLINE', 4000);
define('LISTENQ', 10);
define('PORT', 9105);
define('FD_SETSIZE', 500);
ini_set('SMTP','mail.htnet.hr');
ini_set('sendmail_from' ,'me@mymail.com');
ini_set ('track_errors', 1);
$elapsed="";
$strel="%3E%3E";
function userErrorHandler ($errno, $errmsg, $filename, $linenum, $vars)
{
$dt = date("Y-m-d H:i:s (T)");
$errortype = array (
1 => "Error",
2 => "Warning",
4 => "Parsing Error",
8 => "Notice",
16 => "Core Error",
32 => "Core Warning",
64 => "Compile Error",
128 => "Compile Warning",
256 => "User Error",
512 => "User Warning",
1024=> "User Notice"
);
$user_errors = array(E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE);
if (($errno!=2) && ($errno!=8)) {
$err= "*** Socket Server ".PORT." ****************************\n";
$err .= " Error number : $errno\n";
$err .= " Error type: $errortype[$errno]\n";
$err .= " Error description : $php_errormsg\n";
$err .= "Code line : $linenum\n";
print $err;
mail("design@green-vector.hr","SS Error",$err);
}
}
function flush_buffer($x) {
global $client;
$len=strpos($client[$x][7],"\0")+1;
$sent=socket_write($client[$x][0],$client[$x][7]);
if ($sent===false) {
$client[$x][9]=2;
return;
}
else {
if ($client[$x][9]>0) $client[$x][9]--;
if (($sent>0) && ($sent<=$len) && ($client[$x][9]==0)) $client[$x][7]=substr($client[$x][7],$sent);
}
}
function process_message($i) {
global $client,$strel,$wfds;
$p=strpos($client[$i][6],"\0");
if ($p!==false) {
$n=substr($client[$i][6],0,$p);
$client[$i][6]=substr($client[$i][6],$p+1);
//new client login (this portion sends data to all users)
if ($client[$i][1]==null) {
$client[$i][1]=$n;
for ($j = 0; $j < count($client); $j++) {
if (($client[$j][0]<>$client[$i][0])) {
$client[$i][7].="$j$strel".$client[$j][1]."$strel".$client[$j][3]."\0";
if (in_array($client[$j][0], $wfds)) flush_buffer($i);
}
if (!$client[$j][8]) {
$client[$j][7].="$i$strel".$client[$i][1]."$strel".$client[$i][3]."\0";
if (in_array($client[$j][0], $wfds)) flush_buffer($j);
}
}
return(true);
}
//status change of the player (in the game or on the list)
$sp=split($strel,$n);
if ($sp[0] == 'kraj') {
for ($j = 0; $j < count($client); $j++) {
if ($client[$i][2]==$client[$j][2]) $client[$j][8]=false;
}
return(true);
}
elseif ($sp[0] == 'status') {
$xpl=explode('%7C',$sp[1]);
if (($xpl[0]=='ztv') || ($xpl[0]=='otv') || ($xpl[0]=='igr')) {
if ($xpl[0]=='igr') {
for ($j=0;$j<count($client);$j++) {
if ($client[$i][2]==$client[$j][2]) $client[$j][8]=true;
}
}
$ime=explode($strel,$client[$i][1]);
$client[$i][2]=$ime[1];
$client[$i][3]=$sp[1];
}
else {
if ($client[$i][2]!=$xpl[0]) {
$igraca=0;
for ($j=0;$j<count($client);$j++) {
if ($xpl[0]==$client[$j][2]) $igraca++;
}
if ($igraca>3) return(true);
}
$client[$i][2]=$xpl[0];
$client[$i][3]=$sp[1];
}
}
//this portion sends data only to the users in game room (4 users always)
$chk=0;
for ($j = 0; $j < count($client); $j++) {
if (($client[$i][2]==$client[$j][2]) || ((!$client[$j][8]) && (($sp[0]=='status')||($sp[0]=='call'))) ) {
$client[$j][7].="$i$strel$n\0";
if (in_array($client[$j][0], $wfds)) flush_buffer($j);
$chk++;
}
}
if (($chk!=4) && ($client[$i][8])) print "W:paket od: $i -u grupi: ".$client[$i][2]." -poslan na: $chk soketa\n";
}
}
// *** beginning ***
$old_error_handler = set_error_handler("userErrorHandler");
$listenfd = socket_create(AF_INET, SOCK_STREAM, 0);
if ($listenfd) {
print " ___ SERVER START ___P:9105__________________ \n";
print "| Card game |\n";
print "| WELCOME! |\n";
print "| Playtoy Super Sock Router XVI |\n";
print "| (c)2004-2005 Green-Vector |\n";
print "|____________________________________________|\n";
}
else {
die("SS Error - Socket died!\n");
}
socket_setopt($listenfd, SOL_SOCKET, SO_REUSEADDR, 1);
if (!socket_bind($listenfd, "0.0.0.0", PORT)) {
socket_close($listenfd);
die("SS Error - Couldn't bind!\n");
}
socket_listen($listenfd, LISTENQ);
socket_set_nonblock($listenfd);
/*
Clients (field with data)
0 socket
1 login
2 room
3 status
4 remote host
5 remote port
6 input buffer
7 output buffer
8 flag if user is in started game
9 counter
*/
$client=array();
while(1) {
unset($rfds,$wfds);
$rfds[0] = $listenfd;
for ($i = 0;$i<count($client);$i++) {
$rfds[$i+1]=$client[$i][0];
$wfds[$i]=$client[$i][0];
}
socket_select($rfds, $wfds, $null, null);
if (in_array($listenfd, $rfds)) {
$i=array_push($client,array(socket_accept($listenfd),null,null,'free',null,null,'','',false,0))-1;
socket_setopt($client[$i][0], SOL_SOCKET, SO_REUSEADDR, 1);
socket_set_nonblock($client[$i][0]);
socket_getpeername($client[$i][0], $client[$i][4], $client[$i][5]);
$client[$i][7].=(count($client)-1)."$strel"."Joined$strel".$client[$i][4]."\0";
flush_buffer($i);
if ($i >= FD_SETSIZE) {
trigger_error("Too many clients", E_USER_ERROR);
exit;
}
}
// check the buffer of the clients
for ($i = 0; $i < count($client); $i++) {
if ($client[$i][7]!='') {
flush_buffer($i);
}
if ($client[$i][6]!='') {
process_message($i);
}
}
// check clients /if there are any input data)
for ($i = 0; $i < count($client); $i++) {
if (in_array($client[$i][0], $rfds)) {
$rcv=socket_read($client[$i][0], MAXLINE);
if (!$rcv) {
// close client
for ($j = 0; $j <count($client); $j++) {
if ($client[$i][1]!=null) {
if (($client[$j][2]==$client[$i][2]) || (!$client[$j][8])) {
$client[$j][7].="$i$strel"."gone$strel".$client[$i][1]."\0";
flush_buffer($j);
}
}
}
socket_close($client[$i][0]);
array_splice($client,$i,1);
continue;
}
// buffer (collect whole block)
$client[$i][6].=$rcv;
if (process_message($i)) continue;
}
}
}
?>