文档章节

AngularJS使用websocket从socket.io.client到放弃

SwatNo27
 SwatNo27
发布于 2017/07/19 11:16
字数 1400
阅读 71
收藏 0

首先介绍一下WebSocket,WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。

js创建一个WebSocket对象只需要一个简单的API:

//url, 指定连接的 URL
//protocol 是可选的,指定了可接受的子协议。
let Socket = new WebSocket(url, [protocol] );

 

WebSocket的对象属性

    readyState 表示连接状态,属性值有:0(连接未建立)、1(连接已建立可通信)、2(连接正在关闭)、3(连接已关闭或连接不能打开);

    bufferedAmount 表示已被send()放入队列中等待传输,但是还没有发出的UTF-8文本字节数。

 

WebSocket的事件

    onopen : 连接建立时触发;

    onmessage:客户端接收到服务端数据时触发;

    error: 通信发生错误时触发;

    onclose : 连接关闭时触发。

 

WebSocket的方法

    send():  连接时发送数据;

    close():  关闭连接。

ws = new WebSocket('ws://'+ip+':'+port);
        ws.onopen = function()
        {
            var _connect={"ip":ip,"port":port};
            localStorage.setItem("connect",JSON.stringify(_connect));
            if(!map_json){
                doflag='getMap';
                ws.send("$FILE_READ,1,map.json");
            }
            managerState=true;
        };
        ws.onmessage = function(evt)
        {
            console.log(evt);
            if(evt.data=='$OK'){
                if(switchflag){
                    eval(switchflag+'(evt.data)');
                    if(restart=='eng'){
                        restartEngine();
                        restart=null
                    }
                }
                return
            }
            if(doflag){
            	console.log(evt.data);
                eval(doflag+'(evt.data)');
            }
        };
        ws.onclose = function(evt)
        {
            console.log("WebSocketClosed!");
    
        };
        ws.onerror = function(evt)
        {
            console.log("WebSocketError!");
        };

上面的代码是以前项目中的一部分,为了方便观察一个websocket的基本构成我把里面关于dom操作的内容删掉了,保留的部分代码跟之后项目的移植有关系所以没有删除。不难看出配这样一个webSocket是非常简单的。

 

在angularJS中使用WebSocket

    我的第一个解决方案是使用socket.io-client这个方案是目前比较主流的解决方案,首先我在一个service中引用socket.io.client并将其方法进行封装,代码如下:

import { Observable } from 'rxjs/Observable';
import * as io from 'socket.io-client';

export class ChatService {
  private url = 'http://localhost:8080';
  private socket;

  sendMessage(message) {
    this.socket.emit('add-message', message);
    console.log("MESSAGE SENT");
  }

  getMessages() {
    let observable = new Observable(observer => {
      this.socket = io(this.url);
      this.socket.on('message', (data) => {
        observer.next(data);
      });
      return () => {
        this.socket.disconnect();
      }
    });
    return observable;
  }
}

    这里封装了on和emit两个方法,在我模仿的例子的server启动的时候也确实能够接收和分发数据,但是我遇见了一个很恶心的问题,当我想将其跟我实际项目的websocket的服务器起动后,会发现各种连不上具体表现为ws://127.0.0.1:8888这样的地址最后会被拼接成类似于localhost:ws://127.0.0.1:8888接乱码这样的格式(如果有大佬知道这个问题请务必赐教)

    上面这个问题我在尝试了各种配置都没有解决,连接我例子的地址就是对的,连项目的地址就会报错,而我随便写一个普通websocket就能接收项目的数据,再加上我发现以前的项目里面调用下个方法是这样的

 ws.onmessage = function(evt)
        {
            console.log(evt);
            if(evt.data=='$OK'){
                if(switchflag){
                    eval(switchflag+'(evt.data)');
                    if(restart=='eng'){
                        restartEngine();
                        restart=null
                    }
                }
                return
            }
            if(doflag){
            	console.log(evt.data);
                eval(doflag+'(evt.data)');
            }
        };

通过doflag来确定下个function然后用eval()来调用对应的function,所以我最后放弃了这个方案,因为隐约感觉会出问题,因为之前将threejs的demo移到框架里的时候发现this的指向其实会造成很大的问题。

 

我最后保险起见选用了以最基本的方式使用最简单的websocket

//创建分发器
connectDispather(){
    this.dispather = new WebSocket(this.DISPATH_URL);
    this.dispather.onmessage = (res)=>{
      this.DS.message.next(res);
    };
  }

//发送请求
 getLabelInfo(){
    this.dispather.send('$SUB_ALL');
    this.dispather.send('UPDATE_RAIL');
    this.dispather.send('$UPDATE_GATHER');
    this.dispather.send('$UPDATE_REGION');
    this.dispather.send('$SUB_WARN');
  }


ngOnInit() {
    this.routeSub = this.route.params.subscribe((res) =>{
      this.MANAGER_URL = res.url;
      this.connectManager();
      setTimeout(()=>{this.getLocalizeInfo()}, 100);
    });

    this.connectDispather();
    setTimeout(()=>{this.getLabelInfo()}, 100);//创建dispatch貌似有一点时间间隔如果立即调用send方法会报错

  
  }

这里我分析项目发现其实这个项目总共起了两个websocket复杂的是业务逻辑的连接是通过修改doflag来实现的,而需要数据的页面集中在一个页面,所以其实我只需要单纯的在对应的component上创建对应websocket就行甚至连封成subject都不需要,封成subject虽然能方便的获取到onmessage返回的值,但是其实在send的时候其实不太方便。所以我暂时选择了这个方法。

下面这个是我摸索的时候新建的一个websocket服务,

import { Injectable } from '@angular/core';
import * as Rx from 'rxjs/Rx';

@Injectable()
export class WebSocketService {
  private socket: Rx.Subject<any>;

  private create(url): Rx.Subject<any>{
    let ws = new WebSocket(url);

    let observable = Rx.Observable.create(
      (obs: Rx.Observer<any>)=>{
        ws.onmessage = obs.next.bind(obs);
        ws.onerror = obs.error.bind(obs);
        ws.onclose = obs.complete.bind(obs);

        return ws.close.bind(ws);
      }
    );

    let observer = {
      next: (data: Object)=>{
        if(ws.readyState === WebSocket.OPEN){
          ws.send(JSON.stringify(data));
        }
      }
    };

    return Rx.Subject.create(observer, observable);
  }

  constructor() { }

  public connect(url): Rx.Subject<any>{
    if(!this.socket){
      this.socket = this.create(url);
    }
    return this.socket;
  }

}

最后是google到的一个例子

@Injectable()
export class ChatService {
    public messages: Observable<Message>;
    private ws: Subject<any>;
    constructor() {
        this.ws = Observable.webSocket(CHAT_URL);
        this.messages = makeHot(this.ws).map(parseFrame).filter(m => m != null);
    }

    sendNickMessage(msg: NickMessage) {
        let frame: Frame = {
            type: 'NickMessage',
            data: {
                new_name: msg.newName,
            },
        };
        this.ws.next(JSON.stringify(frame));
    }

    sendChatMessage(msg: ChatMessage) {
        let frame: Frame = {
            type: 'ChatMessage',
            data: {
                body: msg.body,
            },
        };
        this.ws.next(JSON.stringify(frame));
    }

}
import { AfterViewInit ,Component, ViewChild, ElementRef } from '@angular/core';
import { ChatService } from './chat.service';

@Component({
    selector: 'chat',
    template: `
        <div class="messages" #messagesElem>
            <p *ngFor="let msg of messages; let last = last">{{ msg }}</p>
        </div>
    `,
    styles: [
        `:host { overflow-y: scroll; flex: 1; }`,
    ]
})
export class Chat implements AfterViewInit{
    @ViewChild('messagesElem') messagesElem: ElementRef;
    messages: string[] = new Array();

    constructor(
        private chatService: ChatService,
        private elRef: ElementRef,
    ) {
        chatService.messages.subscribe(msg => {
            this.messages.push(msg.toString());
        });
    }

    ngAfterViewInit() {
        let observer = new MutationObserver(() => {
            this.elRef.nativeElement.scrollTop = this.messagesElem.nativeElement.offsetHeight;
        });
        observer.observe(this.messagesElem.nativeElement, { childList: true });
    }
}

 

© 著作权归作者所有

SwatNo27
粉丝 5
博文 15
码字总数 22849
作品 0
成都
前端工程师
私信 提问
AngularBeans —— Java EE 和 AngularJS 集成

Angular Beans 是一个使用 Java EE 7 和 CDI 规范轻松实现在 Java EE 应用中集成 AngularJS 框架的功能。 特性: 可以在 CDI Bean 注入和回调 AngularJS 服务 将 $scope 绑定到 Bean 模型 处...

oschina
2015/06/03
110
0
WebSocket如何穿透Ngrok,或者取消?

请问我在用Angular5开发微信端时,需要在微信Web开发者工具上面调试,但是angular开发时候需要websocket动态刷新页面,请问大家都是如何解决的呢?

哎码
2018/03/29
505
1
PC端网页使用微信扫码获取用户精确地理位置的一种解决方案[未测试]

移动互联网时代,获取用户地理位置来实现LBS当然不再话下。 在传统的PC浏览器应用领域,想获取用户的位置信息一般采用第三方的IP库,比如:淘宝IP地址库。但这种解决方案的缺陷是显而易见的:...

dragon_tech
03/26
0
0
JavaScript 的轻框架开发

为什么我们不用 Angular, Ember 或者 Backbone! Muut 是一个特殊的论坛平台,它也有着巨大的梦想! 当后端的性能已经极大优化的同时,前端也有着自己的目标:简单API,小体积,快速迭代。写...

noonoo
2014/08/29
9.4K
33
使用 Angular/Ngrx 和 Vert.x 构建实时 Web 应用

欢迎来到实时 Web 的世界! 现在是从传统的同步 HTTP 请求/响应架构转移到已连接客户端的响应式应用程序的时候了(这只是一句话中的很多流行语)! 图片来源: https://www.voxxed.com Meteor...

oschina
2017/06/05
3.1K
4

没有更多内容

加载失败,请刷新页面

加载更多

Spring Boot 常用注解说明

实体类 @Entity (实体类注解) @Table(可指定表名) @Data(可缺省get/set) @Id (指定属性主键) @GeneratedValue(指定主键生成规则)

兜兜毛毛
今天
3
0
局域网能互相ping通,ubuntu虚拟机不能上外网

【问题】 桥接模式老是无法上网,查看本机IP发现被分配了一个私网地址,猜测应该是虚拟DHCP服务器没有打开,于是查看Ubuntu的网络配置: /etc/network/interfaces 发现没有dhcp配置的信息,只...

tahiti_aa
今天
2
0
以太坊助记词PHP开发包简介

以太坊助记词PHP开发包用来为PHP以太坊应用增加助记词和层级确定密钥支持能力。下载地址:以太坊助记词php开发包 。 1、开发包概述 以太坊助记词PHP开发包主要包括以下特性: 生成符合BIP39...

汇智网教程
昨天
2
0
系统监控-分布式调用链Skywalking

1. 为什么要使用分布式调用链技术? 随着公司业务的高速发展,公司服务之间的调用关系愈加复杂,如何理清并跟踪它们之间的调用关系就显的比较关键。线上每一个请求会经过多个业务系统,并产生...

秋日芒草
昨天
6
0
告诉自己的一些建议

摆脱学生心态 尽快发挥自己价值,让公司感知自己的存在,才是王道 选择比努力重要 自己附着的平台的经济体要是一个快速崛起的行业 转行趁早,年龄越大选择成本越高 趁早大量试错,学习新领域...

林怡丰
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部