- 浏览: 241685 次
- 性别:
- 来自: 沈阳
文章分类
最新评论
-
Araxis:
也遇到了楼主的问题,我用的sockjs.0.3.4,升级版本到 ...
Websocket出现的错误 -
love_jun1314:
怎么进行转换成功并没有看到a.flv文件呢? 你把commen ...
java调用ffmpeg执行视频转换 -
枫林top:
不错,挺好的
看老外程序员如何向妻子解释设计模式 -
likj_sh:
太感谢了 ,困惑了好久
Struts2 + Spring + Hibernate + DWR 项目布署笔记 -
dhl004:
...
web.xml 通过contextConfigLocation配置spring 的方式
摘要
在上一篇"基础-web即时通讯系统的四种实现"中,我们讨论了socket/tcp相对于其他基于http的通讯方式的优越。本文则详细描述如何使用flash/actionscript,来实现socket/tcp,并使用开源的haxe来编译它。
flash中的socket
socket的构造
实例化一个socket对象,只需要一行代码:
static var socket = new flash.net.Socket();
主动方法和被动方法
而剩下的工作便是把这个对象包装成合适接口供javascript调用了。这时候主要有两类方法,一类是主动性方法,由客户端直接发起的便是主动方法,比如connect、send就是主动方法。
另一类是被动方法,也就是服务器端发起,然后在客户端触发事件,并被调用的回调方法,比如connected、receive就是被动方法。
主动方法和被动方法直接决定了代码的结构,决定了javascript和flash的互操作方式。
事件时序
我们从事件时序上来看一下flash中socket的可能的一个过程:
flash加载完毕
我们先注册一个回调,在flash加载完毕的时候,获得一个通知,以便为下面的连接做一些设置和准备。
flash.external.ExternalInterface.call("setTimeout", jsScope + "loaded()");
建立一个socket连接
接着我们便使用下面的方法来建立一个socket连接
static function connect(host : String, port : String) { trace("Connecting to socket server at " + host + ":" + port); socket.connect(host, Std.parseInt(port)); }
这里的两个形参:host为ip或者域名,port为通讯的端口。trace为输入到flash控制台的方法。
flash socket在端口上是有限制的,仅被允许访问4502-4534这个网段里的端口。
flash socket在执行socket.connect(host, Std.parseInt(port))时,无论如何,会先访问843端口,如果843端口被监听,并且在连接上后接收到一个policy-file.xml的话,才会断开与843端口的连接,并与调用方法时指定的端口连接。
如果flash没有正常得到这个policy-file.xml的话,从调用方法时指定的端口连接时刚连接上便获得这个policy-file.xml也是可以的。如果这两种情况下都没有获得policy-file.xml,那么通讯是不能继续的。这是flash特有的安全机制。
关于这个安全机制,以及提供这个policy-file.xml服务器程序policyserver,我会在稍后的教程里详细介绍。
连接失败
如果flash没有顺利连接上服务器,或者超时,我们可以注册一个回调来获得连接失败的通知,已准备重连。
socket.addEventListener(flash.events.SecurityErrorEvent.SECURITY_ERROR, function(e) : Void { trace("SECURITY ERROR : " + e.text); flash.external.ExternalInterface.call("setTimeout", jsScope + "securityError('" +e.text+ "')", 0); } );
连接成功
如果顺利连接上了,这时候,我们可以通过下面的代码来注册一个回调,得到连接状态更新的通知。
socket.addEventListener(flash.events.Event.CONNECT, function(e) : Void { trace("Connected to server"); flash.external.ExternalInterface.call("setTimeout", jsScope + "connected()", 0); } );
发送消息
下面我们便可以从flash发送消息给服务器了
static function send(msg) { if (socket.connected) { trace("Writing '" + msg + "' to server"); //socket.writeMultiByte(msg,"gb2312"); socket.writeUTFBytes(msg); socket.flush(); } else { trace("Cannot write to server because there is no connection!"); } }
我们可以看到,这段代码里,我注释掉了socket.writeMultiByte(msg,"gb2312");此句代码。从字面意思上也可以了解,这里是使用了"gb2312"的编码来发送消息。
flash socket提供了丰富的方法,在以后的教程里,我会详细描述flash.net.Socket的每一个方法。
获取消息
如果服务器发送消息给客户端,我们也可注册一个回调来获取消息的内容
socket.addEventListener(flash.events.ProgressEvent.SOCKET_DATA, function(e) : Void { //var msg = socket.readMultiByte(socket.bytesAvailable,"gb2312"); var msg = socket.readUTFBytes(socket.bytesAvailable); trace("Received : " + msg ); flash.external.ExternalInterface.call("setTimeout", jsScope + "receive('" + msg + "')", 0); } );
这里和发送消息类似,我们可以使用不同的编码标准来解码我们获得的字节流。
关闭连接
在完成通讯以后,如果我们需要关闭这个socket连接的话,可以使用下面的主动方法。
static function close() { if (socket.connected) { trace("Closing current connection"); socket.close(); } else { trace("Cannot disconnect to server because there is no connection!"); } }
连接断开
在socket连接断开以后,我们可以注册一个回调来获得通知
socket.addEventListener(flash.events.Event.CLOSE, function(e) : Void { trace("Disconnected from server"); flash.external.ExternalInterface.call("setTimeout", jsScope + "disconnected()", 0); } );
IO错误
在通信过程中,如果有错误发生的话,我们可以这样来获得通知
socket.addEventListener(flash.events.IOErrorEvent.IO_ERROR, function(e) : Void { trace("IOERROR : " + e.text); flash.external.ExternalInterface.call("setTimeout", jsScope + "ioError('" + e.text + "')" ,0); } );
完整的代码
//SocketBridge.hx class SocketBridge { static var socket = new flash.net.Socket(); static var jsScope; static function main() { if (flash.external.ExternalInterface.available) { jsScope = flash.Lib.current.loaderInfo.parameters.scope; if (jsScope == null) { jsScope = ""; } else { jsScope += "."; } /* Calls the javascript load method once the SWF has loaded */ flash.external.ExternalInterface.call("setTimeout", jsScope + "loaded()"); // Set event listeners for socket // CONNECT socket.addEventListener(flash.events.Event.CONNECT, function(e): Void { trace("Connected to server"); flash.external.ExternalInterface.call("setTimeout", jsScope + "connected()", 0); } // CLOSE socket.addEventListener(flash.events.Event.CLOSE, function(e): Void { trace("Disconnected from server"); flash.external.ExternalInterface.call("setTimeout", jsScope + "disconnected()", 0); } // IO ERROR socket.addEventListener(flash.events.IOErrorEvent.IO_ERROR, function(e): Void { trace("IOERROR : " + e.text); flash.external.ExternalInterface.call("setTimeout", jsScope + "ioError('" + e.text + "')", 0); } // SECURITY ERROR socket.addEventListener(flash.events.SecurityErrorEvent.SECURITY_ERROR, function(e): Void { trace("SECURITY ERROR : " + e.text); flash.external.ExternalInterface.call("setTimeout", jsScope + "securityError('" + e.text + "')", 0); } // SOCKET DATA socket.addEventListener(flash.events.ProgressEvent.SOCKET_DATA, function(e): Void { //var msg = socket.readMultiByte(socket.bytesAvailable,"gb2312"); var msg = socket.readUTFBytes(socket.bytesAvailable); trace("Received : " + msg); flash.external.ExternalInterface.call("setTimeout", jsScope + "receive('" + msg + "')", 0); } /* Set External Interface Callbacks */ // connect(host, port) flash.external.ExternalInterface.addCallback("connect", connect); // disconnect() flash.external.ExternalInterface.addCallback("close", close); // send() flash.external.ExternalInterface.addCallback("send", send); // log() flash.external.ExternalInterface.addCallback("log", log); } else { trace("Flash external interface not available"); } } /** * Connect to new socket server * @param host The host the socket server resides on * @param port The socket servers port */ static function connect(host: String, port: String) { trace("Connecting to socket server at " + host + ":" + port); socket.connect(host, Std.parseInt(port)); } /** * Disconnect the socket */ static function close() { if (socket.connected) { trace("Closing current connection"); socket.close(); } else { trace("Cannot disconnect to server because there is no connection!"); } } /** * Write string to the socket */ static function send(msg) { if (socket.connected) { trace("Writing '" + msg + "' to server"); //socket.writeMultiByte(msg,"gb2312"); socket.writeUTFBytes(msg); socket.flush(); } else { trace("Cannot write to server because there is no connection!"); } } /** * Log */ static function log(msg) { trace("log : " + msg); } }
编译
我使用了开源的haxe来编译,你也可以通过http://haxe.org/file/hxinst-win.exe获取它。
编写完SocketBridge.hx以后,你需要在同一个目录下建一个compile.hxml文本文件,它的内容是:
-swf socket_bridge.swf -swf-version 9 -main SocketBridge
在安装过haxe的情况下,只要你双击执行compile.hxml,便可以在同一目录下获得编译出的socket_bridge.swf 。
在下一篇教程"客户端-javascript和flash互操作"里,我们将了解如何使用socket_bridge.swf来操作javascript进行socket/tcp通讯。
发表评论
-
用JavaScript玩转游戏物理(一)运动学模拟与粒子系统
2017-09-16 22:28 648系列简介 也许,三百 ... -
30分钟掌握ES6/ES2015核心内容
2017-01-09 11:21 402ECMAScript 6(以下简称ES6)是JavaSc ... -
requirejs、require方法冲突
2016-12-21 18:10 1537如果加载了多个requirejs脚本,每个requirejs ... -
谈谈使用 promise 时候的一些反模式
2016-11-25 15:20 397本文翻译自 We have a problem with ... -
HTML5 Canvas实现平移/放缩/旋转deom示例(附截图)
2016-11-23 12:11 636HTML5 Canvas中提供了 ... -
移动端H5页面高清多屏适配方案
2016-11-17 08:35 823背景 开发移动端H5页面 面对不同分辨率的 ... -
使用Flexible实现手淘H5页面的终端适配rem自适应布局-移动端自适应必备
2016-11-03 23:52 718曾几何时为了兼容IE低版本浏览器而头痛,以为到Mobile时 ... -
CSS3的calc()使用
2016-11-03 21:51 656calc()对大家来说,或许很陌生,不太会相信calc()是 ... -
CSS3的REM设置字体大小
2016-11-03 21:50 668在Web中使用什么单位来定义页面的字体大小,至今天为止都还在 ... -
JavaScript Promises 相当酷
2016-09-02 18:53 511And when I promise some ... -
gulp使用小结
2016-05-22 19:02 644这篇文章不会介绍 gulp 的起源、发展;不会去一个个讲解 ... -
用gulp做一个略完整的前端打包工作
2016-05-22 18:59 2424我们的官网要改版,会从以前的单一产品变成 ... -
前端神器avalonJS入门
2016-05-19 19:32 588本章将介绍如何使用avalon来实现前端路由功能。 我们需 ... -
给Webstorm的HTML自动压缩插件
2016-05-07 14:20 1247前端代码的压缩 前端的js、css、html的压缩不仅会让 ... -
gulp教程之gulp中文API
2016-05-07 13:44 555http://www.ydcss.com/ ... -
gulp详细入门教程
2016-05-07 13:00 546简介: gulp是前端开发过程中对代码进行构建的工具, ... -
HTML5 Boilerplate - 让页面有个好的开始
2016-04-20 19:08 662一:HTML5 Boilerplate是什 ... -
来,让我们谈一谈 Normalize.css
2016-04-20 19:07 443本文译自Normalize.css官网: http:// ... -
Websocket出现的错误
2016-04-06 10:49 6987前端使用sockjs,后台使用spring的websocke ... -
移动平台的meta标签-----神奇的功效
2016-02-18 10:51 458对于桌面平台web布局中大家对meta标签再熟悉不过了,它永 ...
相关推荐
仅使用Python基础从头开始构建大型语言模型;从零开始逐步构建GLM4-Lama3-RWKV6,深入了解大型模型的原理.zip仅使用Python基础从头开始构建大型语言模型;从零开始逐步构建GLM4-Lama3-RWKV6,深入了解大型模型的原理...
这个完整Demo提供了从头开始构建一个简单的客户端和服务端应用程序的基础,特别适合初学者学习网络编程。 **1. SuperSocket简介** SuperSocket设计的目标是让开发者能够快速搭建网络应用,它支持自定义协议,可以...
### 从头开始构建一个嵌入式Linux发行版 #### 目标与概述 本教程旨在展示如何在目标系统上自行构建并安装Linux系统。这一过程并非简单的预装发行版安装,而是通过从零开始的方式,使用户能够在目标设备上运行...
《Python-引导自己从头开始编写一个操作系统》是一本面向自学者的书籍,旨在帮助读者深入理解操作系统的原理,并通过Python语言实现一个简单的操作系统。在学习过程中,你可以掌握计算机系统的基础知识,了解操作...
DIY-Deep-Learning-Workstation, 从头开始构建一个深入学习工作站 DIY-Deep-Learning-Workstation从头构建一个深度学习工作站。 本文档是为 14.04编写的,但大多数步骤也应适用于其他Ubuntu版本和leanring框架。具有...
总的来说,从头开始构建一个App是一项系统性工作,涉及到许多技术细节和决策。"FSKDemo1"作为一个起点,可以让我们逐步了解和掌握这个过程。通过不断学习和实践,我们可以将理论知识转化为实际应用,从而创造出满足...
在计算机网络中,TCP...总的来说,这个项目提供了从头开始理解TCP socket通信的一个基础实例,涵盖了从建立连接、数据传输到关闭连接的全过程。对于学习网络编程和C语言的人来说,这是一个很好的实践案例。
这个项目提供的代码示例("demo7")是一个上位机文件,包含了从头开始构建的详细步骤,非常适合初学者和有经验的开发者作为参考。 首先,让我们理解TCP(传输控制协议)和Socket。TCP是一种面向连接的、可靠的传输...
如果是一个Java项目,通常会包含`.java`源代码文件,开发者可以通过阅读源码来学习如何构建和使用Socket客户端。如果是一个可执行文件,可以直接运行以测试Socket通信。 总的来说,Socket客户端是网络编程中的核心...
mini-arm-os, 从头开始构建 ARM Cortex M 系列的最小多任务操作系统内核 构建最小的多任务操作系统内核先决条件带有STM32微控制器实现的 QEMU 。生成说明./configure --disable-werror --enable-debug --target-list...
我们将从头开始,一步步地搭建整个系统,以便读者能够轻松地搭建自己的 RustDesk 远控软件。 搭建节点服务器 要搭建 RustDesk 远控软件的节点服务器,我们需要满足以下条件: 1. 自有一台服务器 2. 会搭建基本的...
角滚动间谍从头开始构建的简单,轻量级的scroll-spy伪指令。 它在元素滚动到视图或视图之外时广播事件。用法在要为其接收滚动事件的元素上添加scroll-spy属性和id 。 当元素首次滚动到视图中时,会触发一次'...
Java SDK是许多软件开发中的重要组成部分,特别是在与服务器端交互时...通过学习和使用这个SDK,开发者可以迅速在自己的应用中实现稳定、可靠的即时通信功能,而无需从头构建整个通讯系统,大大节省了开发时间和资源。
app-datepicker, 使用聚合物从头开始构建的元件 应用程序 datepicker ( 以前为 jv-datepicker ) 有关详细信息,请参阅组件页 。一个自定义的聚合物元素,从头开始提供一个基于谷歌设计的更具吸引力和丰富性的。实时...
下面,我们将详细讨论如何从零开始构建一个简单的OPC客户端。 **1. 项目设置** 首先,我们需要创建一个新项目。在Visual C++ 6.0中,使用"File" -> "New..."命令创建一个"Win32 Console"类型的项目,并将其命名为...
描述中的“系列”可能意味着这是一个多部分的教程或者项目,逐步引导开发者了解如何从零开始构建一个完整的后台管理系统。企业级后台管理系统通常包括用户管理、权限控制、数据展示、业务流程处理等功能。使用 Vue ...
从头开始构建前端Web应用程序是一个Codecademy Pro Intensive程序,涵盖了专业人员使用React开发Web应用程序所使用的技能。 目录 扫雷车 一个基于控制台的扫雷游戏。 要添加的功能 添加验证以确保电路板尺寸合理。 ...
总的来说,这个压缩包提供了从头开始创建和测试Web服务,再到客户端调用的一系列教程材料。对于想学习或已经在使用MyEclipse和JAX-WS开发Web服务的Java开发者来说,这是一个宝贵的资源。通过阅读文档,实践代码示例...
在本教程中,我们将深入探讨如何使用AngularJS框架从零开始构建一个Web应用程序。AngularJS是Google维护的一个开源JavaScript框架,它主要用于构建单页应用程序(SPA)。这个框架以其数据绑定和依赖注入特性而闻名,...
【标题】:“swift-V2EX的一个第三方iOS客户端” 这个标题表明了我们正在讨论的是一个用Swift编程语言编写的iOS应用程序,它是V2EX社区的第三方客户端。V2EX是一个知名的中文技术交流平台,用户在这里分享各种技术...