使用Redis

时间:2015-06-13 14:38:19

标签: node.js laravel websocket redis

我已经开始使用Laravel 5.1并且它非常棒,只是想通过使用NodeJs作为服务器来玩新的“广播事件”功能,而Redis作为驱动程序遵循指南:http://blog.nedex.io/laravel-5-1-broadcasting-events-using-redis-driver-socket-io/ 。当我触发一个实现ShouldBroadcast接口的事件时,我收到一个错误: “从服务器读取行时出错。[tcp://127.0.0.1:4365]”

4365 - 是运行服务器的端口(在该端口中侦听)。你知道为什么会这样吗?

我还尝试直接使用Redis:

$redis = Redis::connection();
$redis->publish('test-channel', 'msg');

得到相同的结果,“从服务器读取行时出错。[tcp://127.0.0.1:4365]”。

socket.js:

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var Redis = require('ioredis');
var redis = new Redis();

redis.subscribe('test-channel', function(err, count) {
});

redis.on('message', function(channel, message) {
    console.log('Message Recieved: ' + message);
    message = JSON.parse(message);
    io.emit(channel + ':' + message.event, message.payload);
});

http.listen(4365, function(){
    console.log('Listening on Port 4365');
});

设置\ database.php中:

 'redis' => [

        'cluster' => false,

        'default' => [
            'host'     => '127.0.0.1',
            'port'     => 4365,
            'database' => 0,
            'timeout'  => 100,
        ],

    ],

尝试更改defulat超时,将其设置为0,-1或> 10 还尝试在php.ini中禁用Xdebug,问题仍然存在。

我对代码进行了一些调试,试图解决可能导致此问题的原因并且在类中失败:Predis \ Connection \ StreamConnection

public function read()
    {
        $socket = $this->getResource();
        $chunk = fgets($socket);

    if ($chunk === false || $chunk === '') {
            $this->onConnectionError('Error while reading line from the server.');
        }
...
大块是假的为什么? 为什么redis客户端试图从服务器读取数据,因为我理解它应该“发布”到服务器的数据,意味着它应该写(广播)不读取..

2 个答案:

答案 0 :(得分:2)

我认为对Redis的含义存在误解。

  

Redis是一个开源,BSD许可,高级键值缓存商店

它经常用于进程间通信(IPC),它有很好的PUBLISH和SUBSCRIBE命令。

因此,使用Laravel和Node,Redis可以在Node和Laravel的永久运行过程之间进行通信。 Laravel将其事件发布到Redis,Node订阅了Redis的特定频道。在这里,可以通过套接字连接发出消息,很可能是通道名称相同。

要使这一切正常运行,您必须执行以下操作(very well explained in the docs):

  1. 在您的系统上安装Redis。标准端口为6379。
  2. 在composer.json中设置依赖关系:predis / predis~1.0
  3. 在config / database.php中配置Redis。
  4. 将config / broadcasting.php中的Redis设置为Default Broadcaster。
  5. 在config / queue.php中设置默认队列驱动程序。 (注意:如果我将Redis设置为队列驱动程序,事件发布对我不起作用。但是直接发布正在运行<%@ page contentType="text/html; charset=iso-8859-1" language="java" import="java.sql.* "%> <%@ page import="java.io.*"%> <html> <head> <title>Films Example: JSP</title> </head> <body bgcolor="white"> <div> <h1>Filmworld</h1> <table border=1> <tr> <td>imdbID</td> <td>name</td> <td>year</td> <td>rating</td> <td>votes</td> <td>runtime</td> <td>actors</td> <td>genres</td> <td>directors</td> </tr> <% try { String driver = "org.postgresql.Driver"; String url = "jdbc:postgresql://localhost:5432/movie"; String username = "postgres"; String password = "cemcan"; String myDataField = null; String myQuery = "SELECT * FROM movie"; Connection myConnection = null; PreparedStatement myPreparedStatement = null; ResultSet myResultSet = null; Class.forName(driver).newInstance(); myConnection = DriverManager.getConnection(url, username, password); myPreparedStatement = myConnection.prepareStatement(myQuery); myResultSet = myPreparedStatement.executeQuery(); out.println("<table border=1>"); while (myResultSet.next()) { String imdbID = myResultSet.getString("imdbID"); String name = myResultSet.getString("name"); int year = myResultSet.getInt("year"); double rating = myResultSet.getDouble("rating"); int votes = myResultSet.getInt("votes"); int runtime = myResultSet.getInt("runtime"); String directors = myResultSet.getString("directors"); out.println("<tr><td>" + imdbID + "</td><td>" + name + "</td><td>" + year + "</td><td>" + rating + "</td><td>" + votes + "</td> <td>" + runtime + "</td> <td>" + directors + "</td> </tr>"); } out.println("</table>"); myConnection.close(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException ex) { out.print("SQLException: " + ex.getMessage()); out.print("SQLState: " + ex.getSQLState()); out.print("VendorError: " + ex.getErrorCode()); } %> </table> </div> </body> </html> 。也许它是一个Bug?
  6. 现在,您可以创建并触发实现Redis::publish('test-channel', json_encode(['foo' => 'bar']));的事件。出于测试目的,您可以使用:ShouldBroadcast
  7. 现在是切换到Node的时候了: 您的socket.js代码看起来不错,假设Redis在端口6379上。如果Node在本地运行,您可以在浏览器中连接到您的节点服务器,如下所示:Redis::publish('test-channel', json_encode(['foo' => 'bar']));

    这是我在前端和后端测试Node和Socket.io的代码:

    <强> socket.js

    localhost:4365

    <强>的index.html

    var app = require('express')();
    var http = require('http').Server(app);
    var io = require('socket.io')(http);
    var Redis = require('ioredis');
    var redis = new Redis();
    
    
    app.get('/', function(req, res){
        res.sendFile(__dirname + '/index.html');
    });
    
    
    redis.subscribe('test-channel', function () {
        console.log('Redis: test-channel subscribed');
    });
    
    redis.on('message', function(channel, message) {
        console.log('Redis: Message on ' + channel + ' received!');
        console.log(message);
        message = JSON.parse(message);
        io.emit(channel, message.payload)
    });
    
    io.on('connection', function(socket){
        console.log('a user connected');
        socket.on('disconnect', function(){
            console.log('user disconnected');
        });
    });
    
    
    http.listen(3000, function(){
        console.log('listening on *:3000');
    });
    

    我希望这有点帮助:)

答案 1 :(得分:1)

如果在x秒(不是直接)之后收到上述错误,则需要在database.php配置文件中设置读写超时。

如果要将其作为后台任务运行,则以下内容将起作用:

'redis' => [

    'cluster' => false,

    'default' => [
        'host'     => '127.0.0.1',
        'port'     => '6379',
        'database' => 0,
        'read_write_timeout' => -1 
    ],

],