跨平台视频通信项目-OpenTok

简介:

2000元阿里云代金券免费领取,2核4G云服务器仅664元/3年,新老用户都有优惠,立即抢购>>>


阿里云采购季(云主机223元/3年)活动入口:请点击进入>>>,


阿里云学生服务器(9.5元/月)购买入口:请点击进入>>>,

1 理论知识

1.1 OpenTok平台简介

即时视频通信日益成为主流服务,通过WebRTC,开发者可以轻松地将即时视频通信功能加入到应用中。视频聊天创业公司TokBox推出OpenTok,可实现浏览器与iOS设备间跨平台视频聊天。

OpenTok平台可以轻松实现以下功能:

- 高质量的互动视频

- 消息传递

- 屏幕分享

1.2 基本概念

1.2.1 客户端SDK

一组可用于Web(JavaScript),IOS和Android的代码库,用于设置客户端(处理大多数OpenTok的功能能),功能包括

- 发布会话中的流

- 订阅会话中的流

- 监听会话事件

1.2.2 服务器SDK

服务器SDK是部署于应用服务器上,可以使用Node,PHP,Java,.NET,Python和Ruby语言分装OpenTok REST API,为客户端生成新的会话和令牌。

1.2.3 OpenTok REST API

HTTP接口,通过调用该接口可以调用OpenTok服务器SDK的许多方法,其余创建会话和处理高级功能需要由OpenTok Cloud来完成,如归档和广播。

1.2.4 OpenTok Cloud

管理会话,客户端连接,API调用,信令,事件以及客户端SDK或服务器SDK未处理的其他所有内容。

1.3 OpenTok该平台包含库

- Web client libraries(浏览器客户端库)

- IOS client libraries(IOS客户端库)

- Android client libraries(安卓客户端库)

- Server-Side SDKs(服务器端SDK)

- Server-Side REST API(服务器端REST接口)

1.4 系统架构

1.4.1 服务器

- 服务器端SDK支持语言有

 -- Node

 --  PHP

 --  Java

 --  .NET

 -- Python

 -- Ruby

- 服务器端功能生成凭据

1.4.2 客户端

 -- 处理大部分的OpenTok功能

 -- 连接到会话

 -- 将音频视频流发布到会话

 -- 订阅其他客户端的流

1.5 功能阐述

wKiom1lVp9HiWp-AAAFddK5G9ig702.png

1.5.1 客户端

 -- 调用客户端SDK

 -- 从服务器获取会话ID和令牌

 -- 使用令牌连接到会话

 -- 订阅音频视频流

 -- 监听会话事件

1.5.2 应用服务器

- 调用服务器SDK

- 在OpenTok云中创建会话

- 为客户端生成令牌

- 向客户端发送会话ID和令牌

1.5.3 会议

- OpenTok云中的聊天室

- 将客户端彼此连接

- 向客户端发送时间

1.6 OpenTok的通讯过程分析

1.6.1 连接和发布订阅

Step1 由应用服务器创建会话

wKiom1lVqA-wioBGAAFzfcJavqA426.png

应用服务器调用OpenTok服务器SDK代码,通过OpenTok REST API在云中创建一个会话,并取得会话ID,将会议当做视频聊天的房间。

Step2 客户端加载应用程序,服务器创建令牌

wKiom1lVqCTh0O-6AAF6X53c8Js392.png

当用户加载OpenTok Client SDK构建客户端应用程序时,客户端(网页或移动应用程序)从服务器获取会话信息(包括服务器创建的唯一身份验证令牌,相当于客户端与服务器校验的密码)

step3客户端连接并开始流会话流

wKiom1lVqDTQPFwtAAGV-iklD-Q381.png

- 客户端使用会话ID和令牌建立会话连接

- 客户端将音频视频流发布到会话并监听重要事件(例如加入会话的新用户)

step4 新的客户端连接到会话

wKiom1lVqELwZuz5AAGiNM_pgE8647.png

- 当心用户在单独的网页或移动端(客户端2)中加载客户端应用程序时

- 新客户端从应用服务器连接收到会话ID和唯一的令牌

- 客户端使用这些信息来建立会话连接。

step5 客户订阅对方的流

wKiom1lVqFCDqrmeAAGfCj-vwyo729.png

- 新的客户端连接到会话

- 客户端2可以订阅客户端1的流

- 客户端2将自己的视频流发布到会中并且客户端1订阅该视频流

- 两个客户端都一对一地订阅对方视频流,且两端都在倾听新的事件(如新的会话用户)

1.7 开发中心的资源

1.7.1 Helo World

快速演示最基本的OpenTok功能。

https://tokbox.com/developer/quickstart/

1.7.2 教程

构建OpenTok应用程序并添加高级功能逐步演练。

https://tokbox.com/developer/tutorials/

1.7.3 代码示例

使用示例应用程序GitHub repos列表,可帮助你更快地构建应用程序。

https://tokbox.com/developer/samples/

1.7.4 视频聊天嵌入

以最少代码将OpenTok功能集成到你的网站的最快方式。

https://tokbox.com/developer/embeds/

1.7.5 开发人员指南

有关所有OpenTok特点和功能的全面文档,可参考关于Web,IOS和Android的客户端SDK的特定类,方法和事件信息。

https://tokbox.com/developer/guides/

1.7.6 REST API参考文档

使用OpenTok REST API和服务器SDK指南

https://tokbox.com/developer/rest/

1.7.7 开发人员工具

调试会话的有用工具和测试API调用等。

https://tokbox.com/developer/tools/

1.7.8 测试版程序

一个列出所有OpenTok公开Beta以及如何加入他们的页面。

https://tokbox.com/developer/beta/

1.7.9 支持中心

如遇到问题找不到答案,请访问支持中心。

https://support.tokbox.com/

2 实践部分

2.1 部署环境

2.1.1 系统部署

1)最小化安装CentOS 7.3 x86_64,系统信息如下

OS = CentOS 7.3 x86_64

IP Address = 10.168.0.55

HostName = openTok.cmdschool.org

2)名称解析服务

Windows客户端运行里面输入如下命令

1
notepad \Windows\System32\drivers\etc\hosts

并增加如下记录

10.168.0.55 www.cmdschool.org

2.1.2 安装nginx

1
2
yum  install  -y http: //nginx .org /packages/centos/7/noarch/RPMS/nginx-release-centos-7-0 .el7.ngx.noarch.rpm
yum  install  -y nginx

2.1.3 创建项目目录

1
mkdir  -p  /usr/share/nginx/html/opentok

2.1.4 确认配置

1
2
cp  /etc/nginx/conf .d /default .conf  /etc/nginx/conf .d /ssl_default .conf
vim  /etc/nginx/conf .d /ssl_default .conf

确认存在如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
server {
     listen       443;
     server_name  localhost;
     ssl on;
     ssl_certificate 1_www.cmdschool.org_bundle.crt;
     ssl_certificate_key 2_www.cmdschool.org.key;
     ssl_session_timeout 5m;
     ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
     ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
     ssl_prefer_server_ciphers on;
 
     location / {
         root    /usr/share/nginx/html ;
         index  index.html index.htm;
     }
 
     error_page   500 502 503 504   /50x .html;
     location =  /50x .html {
         root    /usr/share/nginx/html ;
     }
}

2.1.5 配置nginx服务

1
2
systemctl  enable  nginx
systemctl restart nginx

2.1.6 配置防火墙

1
2
3
firewall-cmd --permanent --add-service https
firewall-cmd --reload
firewall-cmd --list-all

2.1.7 nginx集成PHP fastCGI

1)安装基础软件包

1
yum  install  -y php-fpm php

2)启动并配置服务自启动

1
2
systemctl  enable  php-fpm.service
systemctl start php-fpm.service

3)配置nginx集成php fastCGI

1
vim  /etc/nginx/conf .d /ssl_default .conf

增加如下代码

1
2
3
4
5
6
7
8
9
     # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
     #
     location ~ \.php$ {
         root            /usr/share/nginx/html ;
         fastcgi_pass   127.0.0.1:9000;
         fastcgi_index  index.php;
         fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
         include         /etc/nginx/fastcgi_params ;
     }

重启nginx服务

1
systemctl restart nginx

4)测试php fastCGI

添加调试代码

1
echo  '<?php phpinfo(); ?>'  /usr/share/nginx/html/index .php

访问以下链接测试fastCGI

https://www.cmdschool.org/index.php

wKioL1lVr6LwKcIUAABhGXFAmok269.png

5)如下日志可以协助你排错

1
2
tail  -f  /var/log/nginx/error .log
tail  -f  /var/log/php-fpm/error .log

2.1.8 安装辅助工具包

1
yum  install  -y unzip

2.2 理解Web客户端会话

2.2.1 配置Index页引用OpenTok.js库

1
vim  /usr/share/nginx/html/opentok/index .html

输入如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<html>
<body>
<!-- OpenTok.js library -->
<script src= "https://static.opentok.com/v2/js/opentok.js" >< /script >
<script>
 
//  credentials
 
 
//  connect to session
 
   
//  create subscriber
 
 
< /script >
< /body >
< /html >

2.2.2 模拟创建服务器凭据

1
vim  /var/www/html/opentok/index .html

内容加入到注释“credentials”下:

1
2
3
var apiKey =  '45828062' ;
var sessionId =  '2_MX40NTgyODA2Mn5-MTQ5NzgzNTA0MjA1NX54WnZGd2VKc3JWTkF3aW04ZlBjTXpKTFV-UH4' ;
var token =  'T1==cGFydG5lcl9pZD00NTgyODA2MiZzaWc9YjVlNjc2ZjJlOTgxOTY1YTJiNGQzMzc1NDZlZmRhYmViZDU1NTNlZjpzZXNzaW9uX2lkPTJfTVg0ME5UZ3lPREEyTW41LU1UUTVOemd6TlRBME1qQTFOWDU0V25aR2QyVktjM0pXVGtGM2FXMDRabEJqVFhwS1RGVi1VSDQmY3JlYXRlX3RpbWU9MTQ5NzgzNTEwMSZub25jZT0wLjA0NDA3NzI3NzgxOTc2MjY3JnJvbGU9cHVibGlzaGVyJmV4cGlyZV90aW1lPTE0OTc5MjE1MDE=' ;

注:必须由服务器创建有效的API秘钥和会话以及令牌

2.2.3 模拟初始化会话

1
vim  /var/www/html/opentok/index .html

内容加入到注释“create subscriber”下:

1
2
3
4
5
6
var session = OT.initSession(apiKey, sessionId)
session.connect(token,  function (error) {
  //  create publisher
  
 
})

2.2.4 模拟发布视频流

1
vim  /var/www/html/opentok/index .html

内容加入到注释“create publisher”下:

1
2
var publisher = OT.initPublisher();
    session.publish(publisher);

代码允许你将网络摄像头和麦克风的音频和视频流发布到会话

2.2.5 创建订阅

1
vim  /var/www/html/opentok/index .html

内容加入到注释“create publisher”下:

1
2
3
session.on( 'streamCreated' function (event) {
  session.subscribe(event.stream);
});

代码允许你在会话中订阅其他客户端的视频流

2.3 配置基本的客户端

2.3.1 创建项目目录结构

1
mkdir  -p  /usr/share/nginx/html/opentok/ {js,css}

2.3.2 创建客户端页面

1
vim  /var/www/html/opentok/index .html

加入如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<html>
< head >
     <title> OpenTok Getting Started < /title >
     <link href= "css/app.css"  rel= "stylesheet"  type = "text/css" >
     <script src= "https://static.opentok.com/v2/js/opentok.min.js" >< /script >
< /head >
<body>
 
     <div  id = "videos" >
         <div  id = "subscriber" >< /div >
         <div  id = "publisher" >< /div >
     < /div >
 
     <script  type = "text/javascript"  src= "js/app.js" >< /script >
< /body >
< /html >

代码作用如下:

- 引用openTok.js库以及自己创建的JS和CSS文件

- 包含发布者与订阅者的DIV

- 将包含视频流

2.3.3 配置认证

1
vim  /usr/share/nginx/html/opentok/js/app .js

加入如下内容:

1
2
3
4
5
6
7
//  replace these values with those generated  in  your TokBox Account
var apiKey =  "YOUR_API_KEY" ;
var sessionId =  "YOUR_SESSION_ID" ;
var token =  "YOUR_TOKEN" ;
 
//  (optional) add server code here
initializeSession();

注:将2.2的apiKey/sessinoId/token值替换变量值。

2.3.4 连接会话并创建发布者

1
vim  /usr/share/nginx/html/opentok/js/app .js

在当前代码后面加入如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//  Handling all of our errors here by alerting them
function  handleError(error) {
   if  (error) {
     alert(error.message);
   }
}
 
function  initializeSession() {
   var session = OT.initSession(apiKey, sessionId);
 
   //  Subscribe to a newly created stream
 
   //  Create a publisher
   var publisher = OT.initPublisher( 'publisher' , {
     insertMode:  'append' ,
     width:  '100%' ,
     height:  '100%'
   }, handleError);
 
   //  Connect to the session
   session.connect(token,  function (error) {
     //  If the connection is successful, publish to the session
     if  (error) {
       handleError(error);
     else  {
       session.publish(publisher, handleError);
     }
   });
}

代码完成以下功能:

- initializeSession函数使用OT.initPubulisher方法创建一个publisher对象,该方法有三个参数, -- publisher视频代替文档对象模型的元素(指ID为publisher的DIV)

 -- publisher属性(insertMode/height/width属性)

 -- 指定完成错误处理

- initalizeSession方法创建一个session对象,该方法需要两个参数,

 -- apiKey,

 -- sessionId

- session.connec方法将客户端程序连接到openTok会话

- 如果连接openTok会话有错误,则将错误对象传递给connect事件处理程序(使用错误消息向控制台发送console.error)

2.3.5 初始化用户

1
vim  /usr/share/nginx/html/opentok/js/app .js

在注释后面加入如下内容:

1
2
3
4
5
6
7
8
//  Subscribe to a newly created stream
session.on( 'streamCreated' function (event) {
   session.subscribe(event.stream,  'subscriber' , {
     insertMode:  'append' ,
     width:  '100%' ,
     height:  '100%'
   }, handleError);
});

- 在会话中创建新流,会话对象调度streamCreated事件。

- 客户端检测到流,我们使用session.subscribe()方法订阅流,该方法需要四个参数,

 -- 客户端订阅的Stream对象(event.stream)

-- 订阅视频代替文档对象模型元素或ID(指ID为subscriber的DIV)

-- 订阅视图的外观属性(指inserMode,height,width属性)

--  错误处理函数(当subscribe方法返回成功或失败时调用)

2.3.6 初始化用户

1
vim  /usr/share/nginx/html/opentok/css/app .css

在注释后面加入如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
body, html {
     background-color: gray;
     height: 100%;
}
 
#videos {
     position: relative;
     width: 100%;
     height: 100%;
     margin-left: auto;
     margin-right: auto;
}
 
#subscriber {
     position: absolute;
     left: 0;
     top : 0;
     width: 100%;
     height: 100%;
     z-index: 10;
}
 
#publisher {
     position: absolute;
     width: 360px;
     height: 240px;
     bottom: 10px;
     left: 10px;
     z-index: 100;
     border: 3px solid white;
     border-radius: 3px;
}

2.4 服务器的部署安装方式概述

2.4.1 选项一Heroku上启动简单的REST服务器

需要简单部署请参阅以下链接:

https://heroku.com/deploy?template=https://github.com/opentok/learning-opentok-php

2.4.2 选项二使用服务器SDK构建(高定制)

需要高级定制请参阅:

https://tokbox.com/developer/sdks/server/

开发者指南请参阅:

https://tokbox.com/developer/guides/

SDK下载地址:

https://github.com/opentok/opentok-php-sdk/releases

PHP语言参考:

http://www.w3school.com.cn/php/php_syntax.asp

2.4.3 选项3服务器实例应用程序

需要实例程序部署请参阅:

https://tokbox.com/developer/samples/

2.5 使用SDK构建服务器

2.5.1 安装composer

1)配置主程序

1
2
3
4
5
php -r  "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r  "if (hash_file('SHA384', 'composer-setup.php') === '669656bab3166a7aff8a7506b8cb2d1c292f042046c5a994c43155c0be6190fa0355160742ab2e1c88d40d5be660b410') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r  "unlink('composer-setup.php');"
mv  composer.phar  /usr/local/bin/composer

2)设置国内源

1
composer config repo.packagist composer https: //packagist .phpcomposer.com

注:其他使用方式请参阅,

https://pkg.phpcomposer.com/

2.5.2 部署基础包

1
2
3
4
5
6
cd  /usr/share/nginx/html
mkdir  backup
mv  opentok backup
composer require opentok /opentok  2.3.1
composer require slim /slim  2.*
composer require gregwar /cache  1.0.*

 配置基础包的权限

1
2
chown  -R nginx:apache  /usr/share/nginx/html
chmod  -R 770  /usr/share/nginx/html

2.5.3 配置php-fpm的启动脚本环境变量

1
cat  /usr/lib/systemd/system/php-fpm .service |  grep  EnvironmentFile

确认包含如下参数:

1
EnvironmentFile= /etc/sysconfig/php-fpm

2.5.4 定义环境变量的参数

1
vim  /etc/sysconfig/php-fpm

输入如下配置:

1
2
API_KEY = 0000000
API_SECRET = abcdef1234567890abcdef01234567890abcdef

注:以上只是范例,API_KEY和API_SECRET需要到云端注册账号申请。

https://tokbox.com/account

2.5.5 systemd的环境变量通过脚本传给bash

1)配置变量传递脚本

1
vim  /etc/profile .d /opentok .sh

输入如下配置:

1
2
3
4
5
6
7
8
9
10
#!/bin/bash
 
if  [ -f  /etc/sysconfig/php-fpm  ];  then
         oldifs=$IFS
         IFS=$ '\n'
         for  in  ` cat  /etc/sysconfig/php-fpm  egrep  - v  "^#|^$|^;"  sed  's/ //g' `;  do
                 export  "$i"
         done
         IFS=$oldifs
fi

2)导入bash的环境变量:

1
source  /etc/profile

3)确认环境变量生效:

1
echo  $API_KEY; echo  $API_SECRET

显示如下:

1
2
0000000
abcdef1234567890abcdef01234567890abcdef

2.5.6 将systemd环境变量传给php-fpm

1)配置变量传递

1
vim  /etc/php-fpm .d /www .conf

注释后加入两行传参变量定义:

1
2
3
4
5
6
7
8
9
10
; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from
; the current environment.
; Default Value: clean  env
; env [HOSTNAME] = $HOSTNAME
; env [PATH] =  /usr/local/bin : /usr/bin : /bin
; env [TMP] =  /tmp
; env [TMPDIR] =  /tmp
; env [TEMP] =  /tmp
env [API_KEY] = $API_KEY
env [API_SECRET] = $API_SECRET

2)通过PHPINFO函数检查传参

wKioL1lVr_TQ73G8AAAdkEdPAuY634.png

注:配置方法详见“2.1.7 nginx集成PHP fastCGI”

2.5.7 修改PHP.ini参数

注:以下全部修改配置文件“/etc/php.ini”,以下配置都需重启“php-fpm”服务

1)显示调试页面

1
display_errors = stderr

2)屏蔽时区错误

1
date .timezone =  "Asia/Shanghai"

2.5.8 代码调试

测试以下链接的代码:

https://www.cmdschool.org/vendor/opentok/opentok/sample/HelloWorld/web/index.php

如果有错误请根据提示修改:

1
vim vendor /opentok/opentok/sample/HelloWorld/web/index .php

2.6 部署项目Demo

2.6.1 下载Demo

如果你不想调试,请使用笔者已经调试过的demo,下载地址如下

http://down.51cto.com/data/2323312

2.6.2 将代码下载到如下目录

1
/usr/share/nginx/html

2.6.3 解压

1
unzip opentok.zip

2.6.4 修改权限

1
2
chown  -R nginx:apache  /usr/share/nginx/html/opentok
chmod  -R 770  /usr/share/nginx/html/opentok

2.6.5 准备调试环境

电脑中需插入如下设备:

- 摄像头(可选)

- 麦克风(必须)

- 耳麦或音箱(可选)

2.6.6 测试运行

使用两个以上的页面打开如下地址:

https://www.cmdschool.org/opentok/index.php

可见如下窗口:

wKioL1lVtYjxC1y4AADIgYUOv58978.png










本文转自 tanzhenchao 51CTO博客,原文链接:http://blog.51cto.com/cmdschool/1943341,如需转载请自行联系原作者
目录
相关文章
|
4天前
嵌入式开发常用的接口和通信协议
本文介绍了嵌入式开发中常见的接口和通信协议,如串口(UART)、COM口、USB口及TTL、RS-232、RS-485电平标准。串口、UART口、COM口和USB口指物理接口,而TTL、RS-232、RS-485则指电平标准。UART通常用于微控制器的串口通信,采用TTL电平;PC的COM口使用RS-232电平。RS-232使用负电压,而RS-485采用差分信号,适合长距离和抗干扰通信。
61 2
|
4天前
|
网络协议 C++
C++ Qt开发:QTcpSocket网络通信组件
`QTcpSocket`和`QTcpServer`是Qt中用于实现基于TCP(Transmission Control Protocol)通信的两个关键类。TCP是一种面向连接的协议,它提供可靠的、双向的、面向字节流的通信。这两个类允许Qt应用程序在网络上建立客户端和服务器之间的连接。Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍如何运用`QTcpSocket`组件实现基于TCP的网络通信功能。
49 8
C++ Qt开发:QTcpSocket网络通信组件
【Xamarin】使用WebSocket开发实时通信应用程序
WebSockets是一种双向通信协议,或TCP连接上的持久通信通道,由许多游戏,具有聊天功能的应用程序和实时应用程序(如股票行情)利用的非常强大的协议。 在这篇博文中,我们将讨论如何构建一个简单的Xamarin聊天室应用程序,该应用程序将利用并连接到ASP.NET Core WebSocket服务。
2905 0
|
4天前
|
存储 网络安全 C++
C++ Qt开发:QUdpSocket网络通信组件
Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍如何运用`QUdpSocket`组件实现基于UDP的网络通信功能。与`QTcpSocket`组件功能类似,`QUdpSocket`组件是 Qt 中用于实现用户数据报协议(UDP,User Datagram Protocol)通信的类。UDP 是一种无连接的、不可靠的数据传输协议,它不保证数据包的顺序和可靠性,但具有低延迟和简单的特点。
22 0
C++ Qt开发:QUdpSocket网络通信组件
|
4天前
|
网络协议 Unix Linux
基础的网络服务器开发
基础的网络服务器开发
|
5月前
|
Dart 监控 开发者
跨平台应用的选择:Flutter下电脑局域网控制软件开发
近年来,跨平台应用的需求不断增加,开发人员纷纷寻找适用于多种操作系统的解决方案。本文将探讨在Flutter框架下开发电脑局域网控制软件的过程,并提供一些实用的代码示例。
245 1
|
网络协议 Ubuntu Linux
基于C++(QT框架)设计的网络摄像头项目(支持跨平台运行)
基于C++(QT框架)设计的网络摄像头项目(支持跨平台运行)
880 0
基于C++(QT框架)设计的网络摄像头项目(支持跨平台运行)
http://www.vxiaotou.com