一、前言

  • socket.io 实现了实时双向的基于事件的通讯机制,是基于 webSocket 的封装,但它不仅仅包括 webSocket,还对轮询(Polling)机制以及其它的实时通信方式封装成了通用的接口,并且在服务端实现了这些实时机制的相应代码
  • socket.io 是跨平台的,可以实现多平台的即时通讯
  • 由于 iOS 端进行 socket 编程主要使用 GCDAsyncSocket 框架,但要实现 Android、iOS、web 多平台的通讯,还是选择统一的框架或协议比较好。
  • 基本 api,使用 socket.on 来监听传过来的数据,使用 socket.emit 来发送数据

二、本例说明

  • 服务器端采用 Nodejs 开启本地服务,统一使用 socket.io 对 iOS 端和 web 进行即时通讯,简单实现类似你猜我画的数据传输
  • 效果

三、服务器端

  • 使用 express 进行简单的搭建,设置模板引擎及静态服务,新手会遇到一个坑,就是路径的问题,一般使用 __dirname,来拼接绝对路径
// 模板引擎
app.set("views", path.join(__dirname, "/views/"));
app.set("view engine", "ejs");
// 静态服务
app.use(express.static(path.join(__dirname, "/public/")));
app.use("/upload", express.static(path.join(__dirname, "/upload/")));
  • 使用 socket.io,来进行 socket 数据监听及数据广播,这是服务器端做的主要事情,本例中传输的数据及格式是自定义的,分为三种,一种是画笔画的路径(path),传输的是一系列的坐标点,一种是图片(img),传输的是 base64 字符串,另一种是发送的文字(text),传输的是字符串
    var http = require('http').Server(app);
var io = require('socket.io')(http); io.on('connection', function (socket) {
console.log('one client connected');
// 连接成功,自己给自己发个空的信息,回调下
socket.emit('connection', null);
// path
socket.on('path', function (msg) {
socket.broadcast.emit('path', msg);
});
// img
socket.on('img', function (msg) {
socket.broadcast.emit('img', msg);
});
// text
socket.on('text', function (msg) {
// 给出自己外的其他所有的 socket 广播
socket.broadcast.emit('text', msg);
// 给所有的 socket 的广播,包括自己
// io.emit('text', msg);
});
});

四、web

  • 关于笔画的传输:使用 canvas,进行画板的相关操作,并保存所有的路径的坐标点,然后 socket 传输
// canvas 绘图
// 拿到 canvas htmlElement
// var canvas = document.getElementById("canvas");
var canvas = $("#canvas").get(0);
// 创建上下文
var ctx = canvas.getContext("2d");
var colorArray = ["black", "red", "blue", "green"];
// 鼠标画图
canvas.onmousedown = function (e) {
// 开始画
ctx.beginPath();
// ctx 属性设置
ctx.lineWidth = 3;
ctx.lineCap = "round";
ctx.lineJoin = "round";
let randomNum = parseInt(Math.random() * colorArray.length);
var mycolor = colorArray[randomNum];
ctx.strokeStyle = mycolor;
// tmp 为装所有坐标点的数组
var tmp = [];
var e = e || window.event;
// 第一个坐标点
var point = {
x: e.clientX - canvas.offsetLeft,
y: e.clientY - canvas.offsetTop
}
ctx.moveTo(point.x, point.y);
tmp.push(point); document.onmousemove = function (e) {
var e = e || window.event;
var point = {
x: e.clientX - canvas.offsetLeft,
y: e.clientY - canvas.offsetTop
}
ctx.lineTo(point.x, point.y);
tmp.push(point);
ctx.stroke();
};
document.onmouseup = function () {
document.onmousemove = null;
document.onmouseup = null; // socket 发送path
var pathDataDict = {
path: tmp,
width: 3,
color: randomNum,
screenW: 400
}
socket.emit("path", pathDataDict);
};
};
  • 关于图片的传输:由于 input type="file" 拿不到本地的图片路径,所以采取先上传图片到服务器,再拿到图片路径,然后通过 canvas 画出来和用 canvas 转换为 base64,然后 socket 发送出去

    • 这里采用 jquery.form 框架,使用 ajax 异步提交表单,新手有个坑,就是 form 里面提交按钮的 type 要设置为 button,不然就是 form submit了,页面会跳转的
$("#selImg").click(function () {
// form 提交
$("#form").ajaxSubmit({
url: "http://127.0.0.1:5000",
type: "post",
dataType: 'json',
success: function (data) {
if (data.status == -1) {
alert("请选择图片发送!");
return;
}
if (data.status == 1) {
alert("图片上传失败!");
return;
} // html Dom Element
let image = new Image();
image.src = "http://127.0.0.1:5000/upload/" + data.status;
image.onload = function () {
ctx.drawImage(image, 0, 0, 400, 400);
var base64Url = canvas.toDataURL("image/png");
let base64 = base64Url.toString()
console.log(base64.substring(22));
socket.emit("img", base64.substring(22)); };
},
error: function (data) { }
});
});
  • 关于文字,就很简单,直接 socket 发送字符串
  • 关于数据的接收,这里要提到一个与 iOS 版 socket.io 不同的地方,在 iOS 端,发送数据是要把数据包装成一个数组的,如 [self.clientSocket emit:@"text" with:@[self.chatTextField.text]];,但在前端接收的数据就直接是 iOS 端数组里的对象,不用取数组第一个,但反过来,在 iOS 端就需要去数组里的第一个了,这里简单说下图片的接收吧,由于对 canvas 不熟,只能采取先创建一个临时的 img 标签展示 base64Url 的图片,然后在 canvas 接收 img 这个 HTMLElement,画出图片,最后删掉这个临时的 img 标签,如果有更好的方法可以留言
socket.on("img", function (msg) {
console.log("img");
// base64 可以直接用<img>展示出来 ,获取 img 标签对象,可画出来
$(".caozuo").append("<img id='tmpImg' width='0' height='0' src='data:image/png;base64," + msg + "'></img>");
ctx.drawImage($("#tmpImg").get(0), 0, 0, 400, 400);
$("#tmpImg").remove();
});

五、iOS

  • 这里官方最新的 socket.io 是只有 swift 版的,之前有旧的oc 版本,但支持的socket.io 是v0.9.x,参考链接 https://github.com/pkyeck/socket.IO-objc,但这很显然不是我想要的,于是开始混编吧
  • 一开始参考了https://github.com/socketio/socket.io-client-swift/issues/393 里的做法,使用 carthage 打包好的 framework,但各种报错
  • 想起之前 oc 调用 swfit 文件,先是直接把 swift 文件拖进工程,然后使用的时候就import "项目名称-swift.h"就行,不需要桥接文件什么的,但在 xcode8 下,貌似感觉还是需要桥接文件。具体做法如下
    • 先拖进一个 swift 文件到 oc 工程里,xcode 会提示创建桥接文件,这里就让 xcode 自动创建桥接文件吧
    • 然后把剩余的 socket.io-client-swift 框架 Source 文件夹里的剩余文件全部拖进 oc 工程
    • 使用的时候就import "项目名称-swift.h"
  • 在 iOS 端下,笔画路径坐标,就直接传输字典就行,我这里字典里包括笔画的颜色,坐标点数组,笔画的宽度及屏幕的宽度等信息,图片就直接传输 base64 的,文字就直接传输字符串,但要注意和 web 端的 socket.io 的区别,具体代码可参考 demo 链接

六、小 demo 地址

七、其他

  • 使用 socket.io,感觉传输数据很方便,api 简单,也没有像 GCDAsyncSocket 传输数据会出现掉包的现象
  • 对于服务器,Nodejs等,我也是新手,如果自己想玩一下的话,可以租国外性价比高的 vps,然后申请域名,可以采取使用 Nginx 做主服务,使用反向代理,这样可方便绑定自己的各种二级域名了,应用服务可以使用 Nodejs 或其他,也可以自己研究下 Nginx 的负载均衡技术了。对与国外 vps 的好处,大家都知道,还可搭建自己的科学上网环境等

基于 socket.io, 简单实现多平台类似你猜我画 socket 数据传输的更多相关文章

  1. socket.io简单说明及在线抽奖demo

    socket.io简单说明及在线抽奖demo socket.io 简介 Socket.IO可以实现实时双向的基于事件的通信. 它适用于各种平台,浏览器或设备,也同样注重可靠性和速度. socket.i ...

  2. socket.io简单入门(一.实现简单的图表推送)

    引子:随着nodejs蓬勃发展,虽然主要业务系统因为架构健壮性不会选择nodejs座位应用服务器.但是大量的内部系统却可以使用nodejs试水,大量的前端开发人员转入全堆开发也是一个因素. 研究本例主 ...

  3. Node中的Socket.IO 简单Demo及说明

    注:下面Demo的Server和Client都是纯后端. 并没有web页面. Server端代码: var express = require('express'); var app = expres ...

  4. 基于react+react-router+redux+socket.io+koa开发一个聊天室

    最近练手开发了一个项目,是一个聊天室应用.项目虽不大,但是使用到了react, react-router, redux, socket.io,后端开发使用了koa,算是一个比较综合性的案例,很多概念和 ...

  5. Socket.IO聊天室~简单实用

    小编心语:大家过完圣诞准备迎元旦吧~小编在这里预祝大家元旦快乐!!这一次要分享的东西小编也不是很懂啊,总之小编把它拿出来是觉地比较稀奇,而且程序也没有那么难,是一个比较简单的程序,大家可以多多试试~ ...

  6. 利用socket.io实现多人聊天室(基于Nodejs)

    socket.io简单介绍 在Html5中存在着这种一个新特性.引入了websocket,关于websocket的内部实现原理能够看这篇文章.这篇文章讲述了websocket无到有,依据协议,分析数据 ...

  7. node基于express的socket.io

    前一段事件,我一个同学给他们公司用融云搭建了一套web及时通信系统,然后之前我的公司也用过环云来实现web及时通信,本人对web及时通信还是非常感兴趣的.私下读了融云和环信的开发文档,然后发现如果注册 ...

  8. Practical Node.js (2018版) 第9章: 使用WebSocket建立实时程序,原生的WebSocket使用介绍,Socket.IO的基本使用介绍。

    Real-Time Apps with WebSocket, Socket.IO, and DerbyJS 实时程序的使用变得越来越广泛,如传统的交易,游戏,社交,开发工具DevOps tools, ...

  9. socket.io搭配pm2(cluster)集群解决方案

    socket.io与cluster 在线上系统中,需要使用node的多进程模型,我们可以自己实现简易的基于cluster模式的socket分发模型,也可以使用比较稳定的pm2这样进程管理工具.在常规的 ...

随机推荐

  1. Spring框架中整合JUnit单元测试的方法

    一. 步骤: 1. 拷贝jar包: 1. JUnit-4.9.jar和spring-test-4.2.4.RELEASE.jar ; 2. 替换原来的main函数: 1. 在测试类上使用注解方式替换: ...

  2. linux apache 打模块示例

    主要是为了以后能举一反三 Apache配置方案 首先,安装apache的一个第三方模块“mod_rpaf”, 官方网站: http://stderr.net/apache/rpaf/ wget htt ...

  3. HTML5 + AJAX ( 原生JavaScript ) 异步多文件上传

    这是在上篇 HTML5 + AJAX ( jQuery版本 ) 文件上传带进度条 的修改版本.后台代码不变就可以接着使用,但是脚本不再使用jQuery了,改为原生的 JavaScript 代码,所以我 ...

  4. iPhone应用中加入评分功能

    NSString *str = [NSString stringWithFormat: @"itms-apps://ax.itunes.apple.com/WebObjects/MZStor ...

  5. Java线程:同步

    一 同步的概念 线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏. 例如:两个线程ThreadA.ThreadB都操作同一个对象Foo对象,并修改Foo对象上的数据. MyRunnab ...

  6. Error while registering Oracle JDBC Diagnosabilityh

    Error while registering Oracle JDBC Diagnosability 把ojdbc6.jar换成ojdbc14.jar就可以了: 后来发现又没有问题了:不过据说这个是数 ...

  7. PHP生成短信验证码

    简单版本 <?php function generate_code($length = 6) { $min = pow(10 , ($length - 1)); $max = pow(10, $ ...

  8. NodeJS的Cluster模块使用

    一.前言大家都知道nodejs是一个单进程单线程的服务器引擎,不管有多么的强大硬件,只能利用到单个CPU进行计算.所以,有人开发了第三方的cluster,让node可以利用多核CPU实现并行. 随着n ...

  9. 算法一之N皇后问题

    (写这篇文章主要是明天就要考试了,算法考试,今天不想再复习了,xiang着今天也开通了博客,于是在这个平台上进行复习,应该会更高效.最后祝愿我明天考个好成绩.嘻嘻...) n皇后问题,主要是应用到回溯 ...

  10. Linux内存管理之slab分配器

    slab分配器是什么? 参考:http://blog.csdn.net/vanbreaker/article/details/7664296 slab分配器是Linux内存管理中非常重要和复杂的一部分 ...