Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

[Client/Server] Socket buffer driving me nuts

Posted on 2004-04-02
6
Medium Priority
?
526 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? ;-)

0
Comment
Question by:brutebass
  • 4
  • 2
6 Comments
 
LVL 27

Expert Comment

by:skullnobrains
ID: 10749503
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.
0
 
LVL 27

Expert Comment

by:skullnobrains
ID: 10749530
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 ?
0
 

Author Comment

by:brutebass
ID: 10756257
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.
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 27

Accepted Solution

by:
skullnobrains earned 2000 total points
ID: 10756738
found something about those functions, check this excellent link.

----------------------------
http://courses.ece.uiuc.edu/ece291/books/labmanual/pmodelib-ref-sockets.html
----------------------------

A.12.22 Socket_recv()
Usage
int Socket_recv(unsigned int Socket, void *Buffer, int MaxLen, unsigned int Flags);

Purpose
Receives data from a connected socket.

Inputs
Socket, a connected socket.

Buffer, the starting address of the buffer to be filled with the incoming data.

MaxLen, the maximum number of bytes to receive.

Flags, bitmask specifying special operation for the function:

Bit 0 = PEEK: peek at the incoming data. The data is copied into the buffer but is not removed from the input queue.

Bit 1 = OOB: get out-of-band data instead of normal data.

Outputs
Returns the number of bytes received, or 0 if the connection has been closed, or -1 on error.
-----------------------------------------------------------


i think that the problem is that when you use &$buffer, you use a link to the adress zone of the variable $buffer.
thus, when you unset ($buffer), you don't change the actual value of the adress space but only break the link between the name of the variable and the adress space.
i thought of a 'scope' issue at first but does not seem to be the case, though i'm no expert :)
i guess u may want to
--- try and globalise the variable, as it may pretty well change the behaving of php concerning that buffer.
--- use a dummy function such as
function dummy_Socket_recv($Socket,$Buffer,$MaxLen,$Flags){
   var $buffer='';//u may call it using 'static' if u want to debug easily
   $num=Socket_recv($Socket, &$Buffer, $MaxLen, $Flags);
   return array($num,$buffer);}
//this simply ruins the point of using a buffer but may help for debugging
--- try this func... should be OK
function reduce_buffer(&$buffer){$buffer='';}
u can't unset the buffer in this way but should be able to reduce it's size to 0

i guess the last one will do the trick properly, but i'm eager to know the results of the other two if u give them a try...

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

Author Comment

by:brutebass
ID: 10757191
"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!

0
 
LVL 27

Expert Comment

by:skullnobrains
ID: 10757729
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.
0

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Author Note: Since this E-E article was originally written, years ago, formal testing has come into common use in the world of PHP.  PHPUnit (http://en.wikipedia.org/wiki/PHPUnit) and similar technologies have enjoyed wide adoption, making it possib…
3 proven steps to speed up Magento powered sites. The article focus is on optimizing time to first byte (TTFB), full page caching and configuring server for optimal performance.
The viewer will learn how to count occurrences of each item in an array.
The viewer will learn how to create a basic form using some HTML5 and PHP for later processing. Set up your basic HTML file. Open your form tag and set the method and action attributes.: (CODE) Set up your first few inputs one for the name and …
Suggested Courses

782 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question