socket.io实践干货

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

一、前言

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

二、本例说明

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

三、服务器端

  • 使用 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 的好处,大家都知道,还可搭建自己的科学上网环境等
谋胆并重
目录
相关文章
|
3月前
|
数据采集 Java 数据挖掘
Java IO异常处理:在Web爬虫开发中的实践
Java IO异常处理:在Web爬虫开发中的实践
|
5月前
|
网络协议 开发者 Python
深度探索Python Socket编程:从理论到实践,进阶篇带你领略网络编程的魅力!
【7月更文挑战第25天】在网络编程中, Python Socket编程因灵活性强而广受青睐。本文采用问答形式深入探讨其进阶技巧。**问题一**: Socket编程基于TCP/IP,通过创建Socket对象实现通信,支持客户端和服务器间的数据交换。**问题二**: 提升并发处理能力的方法包括多线程(适用于I/O密集型任务)、多进程(绕过GIL限制)和异步IO(asyncio)。**问题三**: 提供了一个使用asyncio库实现的异步Socket服务器示例,展示如何接收及响应客户端消息。通过这些内容,希望能激发读者对网络编程的兴趣并引导进一步探索。
61 4
|
6月前
|
程序员 API 开发者
Socket与HTTP协议的实践
【6月更文挑战第4天】本文介绍了Python中的网络编程,包括Socket编程和基于HTTP协议的实践。Socket编程是网络通信的基础,Python的`socket`模块简化了其使用。文中展示了服务器和客户端的简单示例,以及如何通过多线程处理多个客户端连接。另外,文章讨论了HTTP协议,推荐了`requests`库,并给出了发送GET和POST请求的例子。最后,总结了Socket编程和HTTP协议在网络编程中的应用及其在Web开发和API交互中的重要性。
70 5
|
7月前
|
消息中间件 网络协议 前端开发
Socket编程实践模拟通信
Socket编程实践模拟通信
76 0
|
网络协议 Unix Linux
高效网络通信技术揭秘,Socket原理与实践(下)
高效网络通信技术揭秘,Socket原理与实践
|
网络协议 Unix Linux
高效网络通信技术揭秘,Socket原理与实践(上)
高效网络通信技术揭秘,Socket原理与实践
|
域名解析 缓存 网络协议
百度统一socket长连接组件从0到1的技术实践
本文旨在探讨socket长连接技术在移动端的实践,并以iOS端为例,重点分享了百度在实现统一socket长连接组件过程中的技术选型和整体架构设计逻辑。并结合IM即时通讯聊天应用案例,展示长连接组件是如何在移动应用领域为类似业务场景提供解决方案的。
263 0
|
存储 缓存 人工智能
基于文件存储UFS的Pytorch训练IO五倍提升实践
基于文件存储UFS的Pytorch训练IO五倍提升实践
313 0
基于文件存储UFS的Pytorch训练IO五倍提升实践
|
监控 网络协议 Cloud Native
快速界定故障:Socket Tracer网络监控实践
Socket Tracer定位是传输层(Socket&TCP)的指标采集工具,通过补齐网络监控的这部分盲区,来达到快速界定网络问题的目标。
快速界定故障:Socket Tracer网络监控实践
|
网络协议 网络架构
Socket编程实践(1) --TCP/IP简述
ISO的OSI     OSI(open system interconnection)开放系统互联模型是由ISO国际标准化组织定义的网络分层模型,共七层, 从下往上为: OSI七层参考模型 物理层(Physical Layer) 物理层定义了所有电子及物理设备的规范,为上层的传输提供了一个物理介质,本层中数据传输的单位为比特(bit/二进制位)。
1104 0