Search code examples
phpwebsocketphpwebsocket

issue in web-socket php


I have used WebSocket in PHP. but somehow it will close after some time(so many requests).

Is it anyway to handle it?

We got following error when we try to run it after stop:

socket_bind(): unable to bind address [10013]: An attempt was made to access a socket in a way forbidden by its access permissions. in C:\wamp64\www\Websocket\server.php on line 52

Warning: socket_listen(): unable to listen on socket [10022]: An invalid argument was supplied. in C:\wamp64\www\Websocket\server.php on line 55

Here is my code:

<?php
set_time_limit(0);
error_reporting(E_ALL);
//include 'Triangulate.php';

$filename = 'logs.txt';

class Values
{
    public $distance;
    public $rasp_id;
    public $rssi;
}

$host = '10.37.54.167'; //host
$port = '9000'; //port
$null = null; //null var


$rasp = array(
    47 => array(17, 0),
    124 => array(1,6.4),
    43 => array(1,0),
    44 => array(4.6,2));

//Create TCP/IP sream socket
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
//reuseable port
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);

//bind socket to specified host
socket_bind($socket, 0, $port);

//listen to port
socket_listen($socket);

//create & add listning socket to the list
$clients = array($socket);
$distance = array();
$totalbicken = array(array());
//start endless loop, so that our script doesn't stop
while (true) {
    //manage multipal connections
    $changed = $clients;
    //returns the socket resources in $changed array
    socket_select($changed, $null, $null, 0, 10);
    $fp = fopen($filename, 'a+');
    //check for new socket
    if (in_array($socket, $changed)) {
        $socket_new = socket_accept($socket); //accpet new socket
        $clients[] = $socket_new; //add socket to client array
        $header = socket_read($socket_new, 1024); //read data sent by the socket
        perform_handshaking($header, $socket_new, $host, $port); //perform websocket handshake
        socket_getpeername($socket_new, $ip); //get ip address of connected socket
        $response = mask(json_encode(array('type' => 'system', 'message' => $ip . ' connected'))); //prepare json data
        fwrite ($fp,$response . "\n");
      //  send_message($response); //notify all users about new connection
        // send_message_socket($response, $socket_new);
        //make room for new socket
        $found_socket = array_search($socket, $changed);
        unset($changed[$found_socket]);
    }

    //loop through all connected sockets
    foreach ($changed as $changed_socket) {
        //check for any incomming data
        try {
            while (socket_recv($changed_socket, $buf, 1024, 0) >= 1) {
                $received_text = unmask($buf); //Unmask Recive data.
                fwrite ($fp,"Text receive:" . $received_text . "\n");
                $tst_msg = json_decode($received_text); //json decode.
                fwrite ($fp,"Json Decord!". "\n");
                if (!isset($tst_msg->action)) {
                } else {
                    $user_action = $tst_msg->action; //sender name.
                    if ($user_action == "distance") { //If action is distance.
                        $rasp_id = $tst_msg->rasp_id; //get raspberry uniq id.
                        $beacon_id = $tst_msg->beacon_id; //get beacon id
                        $distance_temp = $tst_msg->distance; // get distance
                        $rssi = $tst_msg->rssi; //get RSSI.

                    fwrite ($fp,isset($distance[$beacon_id]). "\n");

                       fwrite ($fp,"Get all values!". "\n");
                        // echo mask(json_encode(array('type'=>'message', 'action'=>'distance', 'beacon_id'=>$beacon_id, 'rasp_id'=>$rasp_id, 'distance'=>$distance)));

                        if (isset($distance[$beacon_id])) {
                            $totalbicken[$beacon_id] = count($distance[$beacon_id]); //get total distance of sender beacon
                        } else {
                            $totalbicken[$beacon_id] = 0;
                        }
                        if (isset($rasp[$rasp_id])) {
                            echo "\nRequest from: " . $rasp_id;
                            $myVal = new Values();
                            $myVal->distance = $distance_temp;
                            $myVal->rasp_id = $rasp_id;
                            $myVal->rssi = $rssi;
                            $flag = false;
                            if (isset($distance[$beacon_id])) {
                                if (count($distance[$beacon_id]) > 0) {
                                    for ($i = 0; $i < count($distance[$beacon_id]); $i++) {
                                        $myTempVal = $distance[$beacon_id][$i];
                                        if (($myTempVal->rasp_id) == $rasp_id) {
                                            $flag = true;
                                            $distance[$beacon_id][$i] = $myVal;
                                            break;
                                        }
                                    }
                                    if (!$flag) {
                                        $distance[$beacon_id][$totalbicken[$beacon_id]] = $myVal;
                                    }
                                } else {
                                    $distance[$beacon_id][$totalbicken[$beacon_id]] = $myVal;
                                }
                            } else {
                                $distance[$beacon_id][$totalbicken[$beacon_id]] = $myVal;
                            }

                            if (count($distance[$beacon_id]) > 2) {
                                /*$data = triangulate($rasp[$distance[$beacon_id][0]->rasp_id], $distance[$beacon_id][0]->distance,
                                $rasp[$distance[$beacon_id][1]->rasp_id], $distance[$beacon_id][1]->distance,
                                $rasp[$distance[$beacon_id][2]->rasp_id], $distance[$beacon_id][2]->distance);*/
                                fwrite ($fp,"Before Triangulation!". "\n");
                                $data = getTrilateration($rasp[$distance[$beacon_id][0]->rasp_id], $distance[$beacon_id][0]->distance,
                                    $rasp[$distance[$beacon_id][1]->rasp_id], $distance[$beacon_id][1]->distance,
                                    $rasp[$distance[$beacon_id][2]->rasp_id], $distance[$beacon_id][2]->distance);
                                fwrite ($fp,"End Triangulation!". "\n");
                                $response_text = mask(json_encode(array('type' => 'message', 'action' => 'distance',
                                'beacon_id' => $beacon_id, 'distance' => $distance[$beacon_id], 'coordinates' => $data)));
                                fwrite ($fp,"Response: ". $response_text . "\n");
                                send_message($response_text);
                            }
                        }
                    }
                    fwrite ($fp,"Break!: ". "\n");
                    break 2; //exist this loop*/
                }
            }
        } catch (Exception $e) {
            fwrite ($fp,"Exception:  done! \n");
            fwrite ($fp,"Exception: ". $e->getMessage(). "\n");
            echo "Exception:" . $e->getMessage();
        }

        $buf = @socket_read($changed_socket, 1024, PHP_NORMAL_READ);
        if ($buf === false) { // check disconnected client
            // remove client for $clients array
            try {
                $found_socket = array_search($changed_socket, $clients);
                socket_getpeername($changed_socket, $ip);
                unset($clients[$found_socket]);
                //notify all users about disconnected connection
                $response = mask(json_encode(array('type' => 'system', 'message' => $ip . ' disconnected')));
                send_message($response);
            } catch (Exception $e) {
                echo "Exception:" . $e;
            }
        }
    }
}
// close the listening socket
socket_close($socket);
$fclose ($fp);

function send_message($msg)
{
    global $clients;
    foreach ($clients as $changed_socket) {
        @socket_write($changed_socket, $msg, strlen($msg));
    }
    return true;
}
function send_message_socket($msg, $changed_socket)
{
    @socket_write($changed_socket, $msg, strlen($msg));
    return true;
}

//Unmask incoming framed message
function unmask($text)
{
    $length = ord($text[1]) & 127;
    if ($length == 126) {
        $masks = substr($text, 4, 4);
        $data = substr($text, 8);
    } elseif ($length == 127) {
        $masks = substr($text, 10, 4);
        $data = substr($text, 14);
    } else {
        $masks = substr($text, 2, 4);
        $data = substr($text, 6);
    }
    $text = "";
    for ($i = 0; $i < strlen($data); ++$i) {
        $text .= $data[$i] ^ $masks[$i % 4];
    }
    return $text;
}

//Encode message for transfer to client.
function mask($text)
{
    $b1 = 0x80 | (0x1 & 0x0f);
    $length = strlen($text);

    if ($length <= 125) {
        $header = pack('CC', $b1, $length);
    } elseif ($length > 125 && $length < 65536) {
        $header = pack('CCn', $b1, 126, $length);
    } elseif ($length >= 65536) {
        $header = pack('CCNN', $b1, 127, $length);
    }

    return $header . $text;
}
//handshake new client.
function perform_handshaking($receved_header, $client_conn, $host, $port)
{
    $headers = array();
    $lines = preg_split("/\r\n/", $receved_header);
    foreach ($lines as $line) {
        $line = chop($line);
        if (preg_match('/\A(\S+): (.*)\z/', $line, $matches)) {
            $headers[$matches[1]] = $matches[2];
        }
    }
    $secKey = $headers['Sec-WebSocket-Key'];
    $secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
    //hand shaking header
    $upgrade = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .
        "Upgrade: websocket\r\n" .
        "Connection: Upgrade\r\n" .
        "WebSocket-Origin: $host\r\n" .
        "WebSocket-Location: ws://$host:$port/Websocket/shout.php\r\n" .
        "Sec-WebSocket-Accept:$secAccept\r\n\r\n";
    socket_write($client_conn, $upgrade, strlen($upgrade));
}

Thanks in advance!


Solution

  • I have setup Linux environment and test. It is working fine. It might a firewall issue in windows.

    As per my knowledge, the newer version of windows (after service pack-3) has some of the RPC rules for connection (Limit of HTTP requests and connection in second) so, that might be an issue.

    Please read this.

    As of now, change the operating system is the one of a solution.

    Thanks & Regards Jignesh M. Mehta