5.4 R语言构建Websocket服务器

问题

R语言怎么实现Websocket?

引言

R语言从一门统计语言正向着工业化语言发展。不仅支持Web的可视化,Web的基本操作,还支持websocket。我们的互联网应用程序不用再绕道Rserve,直接通过Websocket协议,就能实现与R语言的交互。R语言正在发生着技术革命,更先进,更便捷….

5.4.1 websockets介绍

Websocket协议是基于HTML5规范的,在浏览器上实现客户端和服务器端通信的协议。Websocket主要有以下4点优势:1)显著降低网络开销;2)减少服务器的处理开销;3)简化Web服务器端推送数据的模型;4)简化服务器和客户端之间的耦合状态。

websockets包是R语言的一个websocket接口的类库。通过websockets包,可以非常简单地使用R语言构建一个websocket服务器实例。websockets包的API:

  • create_server: 创建一个websocket服务器实例,并绑定端口
  • daemonize: 绑定websocket服务器实例守护进程,到R的控制台,不支持Windows
  • http_response: 发送HTTP Response请求到socket
  • http_vars: 解析HTTP GET/POST参数列表
  • service: 注册websocket实例的服务队列
  • set_callback: 在websocket实例中,定义R函数
  • static_file_service: 静态文件
  • static_text_service: 静态文本
  • websocket: 创建一个websocket客户端实例
  • websocket_broadcast: 向注册在同一个websocket服务器实例的客户端发广播
  • websocket_close: 关闭客户端连接
  • websocket_write: 通过websocket进行数据传输

5.4.2 websockets安装

本节使用的系统环境是:

  • Linux: Ubuntu Server 12.04.2 LTS 64bit
  • R: 3.0.1 x86_64-pc-linux-gnu
  • IP: 192.168.1.201

注:websockets只支持Linux环境。

websockets安装

~ R  # 启动R程序

> install.packages("websockets")  # 安装websockets
> library(websockets)  # 加载websockets
'websockets'R3.0.2

websockets库依赖于caTools库,caTools是一个工具集,请参考1.8节。

补充:websockets包被移出CRAN

笔者在最后2014年4月份整理发现websockets包在2014-03-02时被移出了CRAN库,目前还不知道是什么原因。

原文网页地址 http://cran.r-project.org/web/packages/websockets/index.html

Package ‘websockets’ was removed from the CRAN repository.
Formerly available versions can be obtained from the archive.
Archived on 2014-03-02 at the request of the maintainer.

这样我们在安装websockets包的时候,通过install.packages()的命令就会出错误了。

> install.packages("websockets")
Installing package into ‘/home/conan/R/x86_64-pc-linux-gnu-library/3.0’
(as ‘lib’ is unspecified)

警告信息:

package ‘websockets’ is not available (for R version 3.0.1)

我们需要下载安装包,手动进行安装。

~ wget http://cran.r-project.org/src/contrib/Archive/websockets/websockets_1.1.7.tar.gz  # 下载最新的websockets包
~  R CMD INSTALL websockets_1.1.7.tar.gz  # 在当前目录安装websockets
* installing to library ‘/home/conan/R/x86_64-pc-linux-gnu-library/3.0’
ERROR: dependencies ‘caTools’, ‘digest’ are not available for package ‘websockets’
* removing ‘/home/conan/R/x86_64-pc-linux-gnu-library/3.0/websockets’

安装过程中出现错误,提示为缺少依赖包caTools, digest,所以我们需要先安装这两个依赖包。

~ R   # 启动R程序
> install.packages("caTools")   # 安装依赖包
> install.packages("digest")

~ R CMD INSTALL websockets_1.1.7.tar.gz   # 回到命令行,再次安装websockets包,安装成功
* installing to library ‘/home/conan/R/x86_64-pc-linux-gnu-library/3.0’
* installing *source* package ‘websockets’ ...

** 成功将‘websockets’程序包解包并MD5和检查

** libs

gcc -std=gnu99 -I/usr/share/R/include -DNDEBUG     -DLWS_NO_FORK -fpic  -O3 -pipe  -g  -c libsock.c -o libsock.o
gcc -std=gnu99 -shared -o websockets.so libsock.o -L/usr/lib/R/lib -lR
installing to /home/conan/R/x86_64-pc-linux-gnu-library/3.0/websockets/libs
** R
** demo
** inst
** preparing package for lazy loading
** help
*** installing help indices
** building package indices
** installing vignettes
   ‘websockets.Rnw’
** testing if installed package can be loaded
* DONE (websockets)

~ R  # 启动R程序
> library(websockets)   # 加载websockets包

通过手动的方式,我们就安装好了websockets包。

5.4.3 快速启动websockets服务器demo

websockets包提供了一个demo,通过demo(websockets)函数可以直接启动一个简单的websocket服务器。

> library(websockets)
'websockets'R3.0.2
> demo(websockets)   # 启动demo

查看服务器端进程:

~ netstat -nltp|grep r
tcp        0      0 0.0.0.0:7681            0.0.0.0:*               LISTEN      2231/rsession

在浏览器中打开网页 http://192.168.1.201:7681,我们就能看到websockets实现的demo应用,如图5-4所示。注意,浏览器必须支持HTML5,建议使用chrome浏览器。

websockets的demo应用

图5-4 websockets的demo应用

输出服务器端的日志:

Websocket client socket  20  has closed.
Websocket client socket  8  has been established.
Websocket client socket  21  has closed.

5.4.4 R语言创建websocket服务器实例

接下来,我们创造一个自定义的websocket服务器应用。

~ R   # 打开一个新的R程序
> library(websockets)   # 加载类库
> text = "<html><body><h1>Hello world</h1></body></html>"  # 浏览器的HTTP输出
> w = create_server(port=7681,webpage=static_text_service(text))  # 创建服务实例
> recv = function(DATA, WS, ...){   # 监听receive
+  cat("Receive callback\n")
+  D = ""
+  if(is.raw(DATA)){D = rawToChar(DATA)}
+  cat("Callback:You sent",D,"\n")
+  websocket_write(DATA=paste("You sent",D,"\n",collapse=" "),WS=WS)
+}
> set_callback('receive',recv,w)

> cl = function(WS){   ## 监听closed
+  cat("Websocket client socket ",WS$socket," has closed.\n")
>}
> set_callback('closed',cl,w)

 es = function(WS){ #建立连接
+  cat("Websocket client socket ",WS$socket," has been established.\n")
+}
> set_callback('established',es,w)

> while(TRUE) service(w)   #对所有的连接进行监听

通过上面的代码,我们就创建好了Websocket应用的服务器端部分。

5.4.5 R语言创建websocket客户端连接

接下来,我们再用R语言创建Websocket应用的客户端部分,用Websocket的服务器进行通信。首先在Linux环境中按如下方式新建一个文件client.r:

~ vi client.r
library(websockets)    #加载类库
client = websocket("ws://192.168.1.201",port=7681)   #创建客户端实例
rece<-function(DATA, WS, HEADER) {   D=''   if(is.raw(DATA)){     cat("raw data")     D = rawToChar(DATA)   }   cat("==>",D,"\n")}   #监听receive
set_callback("receive",rece, client)
websocket_write("2222", client)   #向服务器发请求
service(client)    #输出服务器的返回值
websocket_close(client)    #关闭连接

运行客户端口程序:

> library(websockets)
> client = websocket("ws://192.168.1.201",port=7681)
> rece<-function(DATA, WS, HEADER) { +   D='' +   if(is.raw(DATA)){ +     cat("raw data") +     D = rawToChar(DATA) +   } +   cat("==>",D,"\n")}
> set_callback("receive",rece, client)
> websocket_write("2222", client)
[1] 1

> service(client)
raw data==> You sent 2222

> websocket_close(client)
Client socket 3  was closed.

从程序运行的输出,就实现了客户端与服务器端的通信过程。

5.4.6 用浏览器HTML5原生API客户端连接

接下来,我们在chrome浏览器中,编写Javascript代码,调用原生的HTML5的API访问Websocket服务器。在Chrome浏览器中打开网页:http://192.168.1.201:7681 ,按F12 打开“开发者工具”再切换到Javascript控制台 “Console”,在Console中输入Javascript程序代码,如图5-5所示。

浏览器原生Javascript访问Websocket服务器通信

图5-5 浏览器原生Javascript访问Websocket服务器通信

原生的HTML5程序

var ws = new WebSocket("ws://192.168.1.201:7681");
ws.onopen = function(){
console.log("connecting");
};
ws.onmessage = function(message){
console.log(message.data);
console.log(message);
};
function postToServer(msg){
ws.send(msg);
}
function closeConnect(){
ws.close();
console.log("closed");
}

postToServer('browser');
closeConnect();

我们这样就完成了,R语言构建的Websocket服务器测试,又给R语言与其他语言通信打开了一条便利的通道。

results matching ""

    No results matching ""