PHP 请求到 PHP Websocket [英] PHP request to PHP Websocket

查看:35
本文介绍了PHP 请求到 PHP Websocket的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻求有关 websocket 问题的帮助.我构建了一个简单的 HTML5 websocket 来连接我的 AngularJS-Site(websocket 通过简单的 JS 连接)和我的 PHP-Server.连接也能正常工作,发送和接收数据也能正常工作.我需要 websocket 的原因是:我在同一台服务器上有一个不同的 REST-Service (PHP),它也与 AngularJS-Site 进行通信.因此 REST-Service 更改数据库中的数据.现在,当我从 AngularJS-Site(例如创建一个新用户)启动一个操作时,REST-Service 在作业列表中创建一个作业,该作业将从任何其他服务(不相关)执行,经过一段时间后几秒钟后,如果工作完成,该服务将向 REST-Service 发出信号.作业将设置为完成(在数据库中).

I'm searching for help with my websocket problem. I have built a simple HTML5 websocket to connect between my AngularJS-Site (websocket connects through simple JS) and my PHP-Server. The connection works as well, and also sending and recieving data works as well. The reason, why I need a websocket is: I have a diferent REST-Service (PHP) at the same server, which also communicates with the AngularJS-Site. So the REST-Service changes data at a Database. Now, when I kick an action from the AngularJS-Site (create a new user for example), the REST-Service creates a job in a joblist, and the job will be performed from any other service (not relevant), and after some seconds, the service will give a sign to the REST-Service, if the job is done. The job will be set to done (in the database).

现在,当作业设置完成时,我需要从 REST-Service 向 PHP Websocket 发送请求,Websocket 应该向 angularJS-Site 发送消息.我知道,我可以通过 Angular-JS 进行轮询,但这会产生太大的流量,因为很多用户会同时使用该系统.

Now, at this point as the job is set to done, i need to send a request from the REST-Service to the PHP Websocket, ant the Websocket should send a message to the angularJS-Site. I know, i could polling through Angular-JS, but that would create too big traffic, beacuse many users will use that system at the same time.

抱歉我的解释不好(还有我糟糕的英语 - 我是德国人;)).

Sorry for my bad explanation (and also for my bad english - i'm german ;)).

我的简单问题:是否有可能将请求从 PHP REST-Service 发送到 websocket,因此 websocket 会通知我的 angular:工作已完成.

这个简单的请求是否可行,或者我是否需要创建一个 PHP 客户端,它会一遍又一遍地刷新数据库以检查工作是否完成并通过 websocket 发送到 angular?还有其他想法吗?

Is that simple request possible, or have I to create a PHP Client which refreshes over and over the database to check, if the job is done and send then to the angular through the websocket? Any other ideas?

感谢您的帮助!

也许正如所说的一些代码会很好:).只有一些标准的 HTML5 websocket,但也许它会有所帮助:

Maybe as said some code would be good :). There's only some standart-HTML5 websocket, but maybe it would help:

JS(在 angulars 配置方法中):

JS (in angulars config-method):

//configure websocket
var uri= "ws://x.x.x:9000/websocket/websocket.php";     
ws= new WebSocket(uri); 

ws.onopen = function(ev) { // connection is open 
    console.log("Websocket: Connection established");
}

ws.onmessage = function(ev) {
    console.log(ev.data);
};

ws.onerror = function(ev){
    console.log("Websocket: Connection Error: " + ev.Error);}; 

ws.onclose = function(ev){
    console.log("Websocket: Connection closed");};     

这就是 PHP-Websocket(在互联网上找到):

Thats the PHP-Websocket (found on internet):

$host = 'lucadev.lonzagroup.net'; //host
$port = '9000'; //port
$null = NULL; //null var

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($socket, 0, $port);
socket_listen($socket);
$clients = array($socket);

//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);

    //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
        send_message($response); //notify all users about new connection

        //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
        while(socket_recv($changed_socket, $buf, 1024, 0) >= 1)
        {
            $received_text = unmask($buf); //unmask data
            $tst_msg = json_decode($received_text); //json decode 
            $user_name = $tst_msg->name; //sender name
            $user_message = $tst_msg->message; //message text
            $user_color = $tst_msg->color; //color

            //prepare data to be sent to client
            $response_text = mask(json_encode(array('type'=>'usermsg', 'name'=>$user_name, 'message'=>$user_message, 'color'=>$user_color)));
            send_message($response_text); //send data
            break 2; //exist this loop
        }

        $buf = @socket_read($changed_socket, 1024, PHP_NORMAL_READ);
        if ($buf === false) { // check disconnected client
            // remove client for $clients array
            $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);
        }
    }
}
// close the listening socket
socket_close($sock);

function send_message($msg)
{
    global $clients;
    foreach($clients as $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: wss://$host:$port/websocket/websocket.php\r\n".
    "Sec-WebSocket-Accept:$secAccept\r\n\r\n";
    socket_write($client_conn,$upgrade,strlen($upgrade));
}    

我不认为,REST-Service 是相关的.

I don't think, the REST-Service is relevant.

编辑 2我认为,对我来说唯一的解决方案(在你说之后,一个简单的请求是不可能的)是创建一个与 websocket 通信的单独类(php).它将打开一个连接发送,工作完成,并最终关闭它.那应该对我有用,不是那么优雅,但应该有用.感谢帮助!

Edit 2 I think, the only solution for me (after you said, a simple request is not possible) is to create a seperate class (php) which communicates with the websocket. It will open a connection to send, that the job is done, and close it after all. That should work for me, not that graceful, but should work. Thanks for help!

推荐答案

Sam,

看看ThruwayWampPostAngular-WAMP.这些项目使用一种名为 WAMP 的协议,该协议允许不同的组件通过 Websocket 相互通信.

Take a look at Thruway, WampPost and Angular-WAMP. These projects use a protocol called WAMP, which allows different components to talk to each other over Websockets.

您的设置将如下所示:

[WampPost 客户端]<---->[Thruway WAMP 路由器]<---->[Angular 客户端]

[WampPost Client]<---->[Thruway WAMP Router]<---->[Angular Client]

我会给你一些快速的代码示例,这样你就可以看到它们是如何协同工作的,但你需要去每个单独的项目看看如何配置每个组件.

I'll give you some quick code samples, so you can see how it all works together, but you'll need to go to each individual project to see how to configure each component.

高速公路路由器:

<?php
    require 'vendor/autoload.php';
    use Thruway\Peer\Router;
    use Thruway\Transport\RatchetTransportProvider;

    $router = new Router();

    //Websockets listen on port 9090
    $transportProvider = new RatchetTransportProvider("127.0.0.1", 9090);
    $router->addTransportProvider($transportProvider);

    //WampPost Client listens on port 8181
    $router->addInternalClient(new \WampPost\WampPost('realm1', null, '127.0.0.1', 8181));        

    $router->start();

角度:

app.config(function ($wampProvider) {
    $wampProvider.init({url: 'ws://127.0.0.1:9090/',realm: 'realm1'});
})
app.run(function($wamp){
    $wamp.open(); //This will open the connection when the app starts
})
app.controller("MyCtrl", function($scope, $wamp) {
   // Subscribe to a topic
   function onevent(args) {
      $scope.hello = args[0];
   }
   $wamp.subscribe('com.myapp.hello', onevent);      
});

使用请求/响应发布消息.这可以通过 PHP、Curl 或任何可以发出 HTTP 请求的东西来完成.

Publishing a message with Request/Response. This can be done from PHP, Curl or anything that can make an HTTP request.

curl -H "Content-Type: application/json" -d '{"topic": "com.myapp.hello", "args": ["Hello, world"]}' http://127.0.0.1:8181/pub

现在订阅主题com.myapp.hello"的每个人都会收到消息Hello, world".

Now everyone that has subscribed to the topic "com.myapp.hello", will receive the message "Hello, world".

这只是一个非常基本的例子.您可以使用 WAMP 做更多事情,包括 RPC 和 websocket 身份验证.

This is just a very basic example. You can do a lot more with WAMP, including RPCs and websocket authentication.

另外,我是 Thruway 的开发者之一,所以如果您有任何问题或一般性问题,请告诉我.

Also, I'm one of the developers of Thruway, so if you have any issues or general questions, let me know.

这篇关于PHP 请求到 PHP Websocket的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆