2

We're using a system at the moment that takes an incoming JSON request over TCP and responds using JSON too. Currently I've set up my socket like so in PHP:

$socket = fsockopen($host, $port, $errno, $errstr, $timeout);

if(!$socket)
{
  fwrite($socket, $jsonLoginRequest); // Authentication JSON

  while(json_decode($loginResponse) == false) // We know we have all packets when it's valid JSON.
  {
     $loginResponse .= fgets($socket, 128);
  }

  // We are now logged in.

  // Now call a test method request
  fwrite($socket, $jsonMethodRequest);

  while(json_decode($methodResponse) == false) // We know we have all packets when it's valid JSON.
  {
     $methodResponse .= fgets($socket, 128);
     echo $methodResponse; // print response out
  }

  // Now we have the response to our method request.
  fclose($socket);
}
else
{
  // error with socket
}

This works at the moment, and the server responds to the method request. However, some methods will respond like this to acknowledge the call, but will also respond later on with the results I'm after. So what I really need is a TCP listener. Could anyone advise how I could write a TCP listener using fsock like I have above?

Thanks

ingh.am
  • 25,981
  • 43
  • 130
  • 177

1 Answers1

3

To create a listening socket use the following functions:

I'm not shure if fwrite()/fread() are working with those sockets otherwise you have to use the following functions:

Message-loop

I have now written some function to read a single JSON responses with the assumption that multiple responses are separated by CRLF. Here's how I would do it (assuming your php-script has unlimited execution time):

// ... your code ... 

function readJson($socket) {
    $readData = true;
    $jsonString = '';
    while(true) {
        $chunk = fgets($socket, 2048); 
        $jsonString .= $chunk;

        if(($json = json_decode($jsonString)) !== false) {
            return $json;
        } elseif(empty($chunk)) {
            // eof
            return false;
        }
    }
}

// ....
// Now call a test method request
fwrite($socket, $jsonMethodRequest);

$execMessageLoop = true;
while($execMessageLoop) {
    $response = readJson($socket);
    if($response === false) {
        $execMessageLoop = false;
    } else {
        handleMessage($socket, $response);
    }
}

function handleMessage($socket, $response) {
    // do what you have to do
}

Now you could implement the "handleMessage" function which analyses the response and acts to it.

vstm
  • 12,407
  • 1
  • 51
  • 47
  • Having a bit of an issue with socket_create_listen `unable to bind to given adress [98]: Address already in use`. This is using the same port I am using with fsockopen. – ingh.am Aug 05 '11 at 13:51
  • You said it responds later... do you mean on the same socket-connection or does the server open a new connection to a listening socket (in which case you have to use an other port)? If it responds later on the same connection you don't need the socket_* functions. Use [stream_select](http://www.php.net/manual/en/function.stream-select.php) instead to wait for the data. But beware of the php max-execution timeout which may still apply. – vstm Aug 05 '11 at 14:00
  • If I call the command in bash it does it on the same connection. The problem with my script above is that it just reads data until a valid JSON is returned. What I really need is a never-ending loop that checks for incoming responses and I can deal with them accordingly. – ingh.am Aug 05 '11 at 14:47
  • Okay, so the problem is that it stops after the first JSON is received? Well then you have to wrap the receiving part in another loop so that the reading is executed multiple times. What's also important is how the JSON-messages are separated, are they separated by CRLF (I just assume this since you're using gets) or some other delimiter? I have implemented my suggestion in the answer. – vstm Aug 05 '11 at 15:32