Play框架是使用Iteratees, Enumerators, 和 Enumeratees之类抽象以一种函数式编程方式进行流处理,如Comet, chunked responses分块响应, WebSockets。
在Javascript那边, Node.js的socket.io是使用EventEmitter API通过命令式编程方法进行流处理。这个方法简单易学。
下面以一个案例,重点将放在WebSockets ,包括基本的“Hello World ”的例子,一个echo服务器,以及一个简单的聊天应用程序。
Producer生产者, consumer消费者, adapter适配器
Iteratee, Enumerator, 和 Enumeratee概念让人迷惑,让我们还是用人类概念来解释一下他们:
Enumerator: 实际就是生产者,这是发出数据块的地方。
Iteratee: 实际就是消费者。他们是Java迭代器的反转:在一个Iterator中你定义“next”是请求下一个数据块,在Iteratee中,你定义了一个“fold”方法,是对每个数据块做出反应react(控制反转)。
Enumeratee: 实际是Adapter适配器, Enumeratees可以附加在Iteratees前以便修改通过他们的流数据。
Hello World案例
开始一个hello world的websocket案例,首先你要监听socket, NodeJS的代码如下:
var io = require('socket.io').listen(80); io.sockets.on('connection', function (socket) { console.log("Someone just connected!"); });
|
在Play框架中,你会创建一个WebSocket Action,然后返回Enumerator,它用来发送消息给客户端,还有 Iteratee 是用来对来自客户端的消息即时反应. 第一个版本返回Enumerator 和 Iteratee暂时什么都不做。
object Socket extends Controller { def connect = WebSocket.using[String] { request => Logger.info("Someone just connected!") // For this first example, we return an Iteratee and // Enumerator that do nothing (Iteratee.ignore, Enumerator.empty) } }
|
需要把这个端点配置在路由文件中:
GET /connect controllers.Socket.connect
现在你可以使用 ws://localhost:9000/连接了,连接客户端在http://www.websocket.org/echo.html
下面开始加入发送消息功能,在node.js增加了一行
/ Send a message to the client
socket.emit('message', "Hello!");
在Play框架中,我们创建Enumerato,可以从来自File, InputStream, OutputStream, a Future等来源创建它,这里只用一个固定数据集来创建它。
object Socket extends Controller { def connect = WebSocket.using[String] { request => Logger.info("Someone just connected!") // Create an Enumerator that sends a message to the // client 创建Enumerator val enumerator = Enumerator("Hello!") (Iteratee.ignore, enumerator) } }
|
最后一个功能接受客户端的消息,在Node.js:
var io = require('socket.io').listen(80); io.sockets.on('connection', function (socket) { console.log("Someone just connected!"); // Send a message to the client socket.emit('message', "Hello!"); // Listen for messages from the client socket.on('message', function (message) { console.log("Got message: " + message); }); });
|
在Play框架中,我们必须创建一个Iteratee来监听来自客户端的消息。Iteratee有几个方法,“消费”(消费将所有的数据),“头”(消费的数据只是第一个块),和“foreach”,它为每个数据块提供触发一个回调。
object Socket extends Controller { def connect = WebSocket.using[String] { request => Logger.info("Someone just connected!") // Create an Enumerator that sends a message to the // client val enumerator = Enumerator("Hello!") // Create an Iteratee that listens for messages from // the client val iteratee = Iteratee.foreach[String] { msg => Logger.info(s"Got message $msg") } (iteratee, enumerator) } }
|
更深入案例见原文:
Play, Scala, and Iteratees vs. Node.js, JavaScript, and Socket.io