We help IT Professionals succeed at work.

[Client/Server] Socket buffer driving me nuts

brutebass
brutebass asked
on
Medium Priority
602 Views
Last Modified: 2008-03-17
the following problem is driving me nuts, i've search everywhere, tried and tried over and over again, but i just can't figure out how to delete the contents in $buffer in the following (simplified) code:

[code]
<?

define("LF", "\r\n");
echo "Init\n";

/* Allow the script to hang around waiting for connections. */
set_time_limit(0);

/* Turn on implicit output flushing so we see what we're getting as it comes in. */
ob_implicit_flush();

$address = "x.x.x.x";
$port = 1445;
$max_clients = 10;

// Array that will hold client information
$clients = array();
$read = array();
$buffer = ""; /* create buffer */

echo "Creating socket...".LF;
// Create a TCP Stream socket
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

echo "Binding socket...".LF;
// Bind the socket to an address/port
socket_bind($sock, $address, $port) or die("Could not bind to address");

echo "Listening...".LF;
// Start listening for connections
socket_listen($sock);

// Loop continuously
while (true) {
      
      // Setup clients listen socket for reading
      $read[0] = $sock;
      for ($i=0; $i<$max_clients; $i++) {
                  if ($clients[$i]["sock"] != null) {
                        $read[$i+1] = $clients[$i]["sock"];
                  }
      } // end for ($i=0
      
  // Set up a blocking call to socket_select()
      socket_select($read, $write=NULL, $except=NULL, 15);
      
      /* if a new connection is being made add it to the client array */
      if (in_array($sock, $read)) {
            
            $clientsLength = count($clients);
            if ($clientsLength >= $max_clients) {
                  echo "Too many clients".LF;
            } else {
                  
                  echo "Adding client $clientsLength...".LF;
                  $clients[$clientsLength]["sock"] = socket_accept($sock);
                  socket_getpeername($clients[$clientsLength]["sock"], &$clients[$clientsLength]["IP"]);
                  echo "New connection from ".$clients[$clientsLength]["IP"]."...".LF;
                  
                  /* send welcome message */
                  $output = "Welcome to my test server :P".LF.chr(0);
                  socket_write($clients[$clientsLength]["sock"], $output, strlen($output));
            }
                        
      } // end if in_array
      
      $clientsLength = count($clients);
      //echo "Total clients: $clientsLength".LF;
      
      // If a client is trying to write - handle it now
      for ($i=0; $i<$clientsLength; $i++) { /* for each client */
                  
                  unset($buffer);
                  $buffer = "";
                  if (in_array($clients[$i]["sock"], $read)) {

                        // ** PROBLEMATIC STUFF STARTS HERE **
                        $input = socket_recv($clients[$i]["sock"], &$buffer, 8, PHP_BINARY_READ);

                        if ($input == 0) {
                              echo "Client ($i) disconnected".LF;
                              // Zero length string meaning disconnected
                              unset($clients[$i]);
                        } else {

                              if ($input == "exit") {
                                          // requested disconnect
                                          socket_close($clients[$i]["sock"]);
                              } else {

                                    echo "input: $input, $buffer (".strlen($buffer)."):".LF;
                                    for ($k=0; $k<strlen($buffer); $k++) {
                                          echo ord(substr($buffer, $k, 1))." | ";
                                    }
                                    
                                    echo LF;
                                    
                              
                              }
                        }
                        
                  } else {
                        echo "$i not in array".LF;
                  } // end if (in_array(
                  
      } // end for ($i=0;
      
} // end while (true)

echo "Destroying master socket...".LF;
// Destroy master socket
socket_close($sock);
?>

the code above is far from pretty, but it works.
I can send and recieve from any client connected (using Telnet to connect to port).
But when $buffer has reached the size of 8, the buffer is full and i am no longer abled to read anymore incoming data from the client.

How can i empty/reset/unset the buffer?

I tried the following, but it doesnt seem to work:
[code]
$buffer = "";
unset($buffer);
[/code]

Buffer seems to be stored somewhere php can't write? On an even lower level?

I use socket_recv() because socket_read() does not work on Win32/CLI (PHP4.3.5 and PHP5.0.0 RC1). And i want my code to be abled to run on Win32 and on Linux.

Anyone with some more experience with this than me? ;-)

Comment
Watch Question

CERTIFIED EXPERT

Commented:
i don't get it really but &$buffer is the address of the variable so i guess once u set anything through this way, u have to delete using the adresses themselves ie loop through the adresses (as a string is an array of letters and adresses are --not sure-- indexed in a linear manner).
can u post something about the socket_recv() function. it does not seem to be documented in the manuals i looked in... or maybe there is a similar function whicth will let you binary-crush the adresses...
hope that helps.
CERTIFIED EXPERT

Commented:
just another thing :
did $buffer change in the pointer to the variable $buffer ? in which case the variable might stay defined somewhere while u only delete the pointer ?
what would echo $buffer and typeof($buffer) output ?

Author

Commented:
gettype($buffer) returns 'string'

about socket_recv: i don't know more than you, all i've got is the manual :)
int socket_recv ( resource socket, string &buf, int len, int flags)
flags can be PHP_NORMAL_READ or PHP_BINARY_READ. With PHP_NORMAL_READ socket_recv will return data when a CRLF (or just LF, i dont know) is received.
socket_recv fills $buffer with data from the socket and seems to return the length of $buffer.

setting $buffer[$i], with $i as an integer ranging from 0 to length of $buffer, doesnt work either.
CERTIFIED EXPERT
Commented:
Unlock this solution and get a sample of our free trial.
(No credit card required)
UNLOCK SOLUTION

Author

Commented:
"my comment about 'looping' through the adresses was probably nonsense in php. got any hints on that part ?"

Yes, that was nonsense :-)


Very useful link!
After reading I tried using:

int Socket_recv(unsigned int Socket, void *Buffer, int MaxLen, unsigned int Flags)

with the values of Flags as 0, 1, 2, PHP_NORMAL_READ and PHP_BINARY_READ. The $buffer is gone after reading when using 0.
PHP_NORMAL_READ and PHP_BINARY_READ are synonyms for respectively 1 and 2, which both didnt give the desired result.

Globalising $buffer does not work, it really has something to do with a low level socket function which keeps an internal buffer, as proven.
Also tried your dummy_socket solution, but this got kinda complicated, it might work i guess, but not really usefull anymore, because a 0-flag simply works :-)

Thanks your effort!

CERTIFIED EXPERT

Commented:
happy that u managed, and that the link was usefull though i definitely couldn't have figured out that flag thing myself as i'm quite new to lower-level programing... ;)

btw that coding seems bound to great expectations ! cheers for the rest.
Unlock the solution to this question.
Thanks for using Experts Exchange.

Please provide your email to receive a sample view!

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.