精华内容
下载资源
问答
  • nginx 配置websocket长连接ws协议

    千次阅读 2019-12-27 15:49:15
    利用 ip + prot 连接websocket服务器,缺点: 1. 暴露服务器地址和端口; 2.只能单节点部署,无法做集群; 3. 诸多缺点。 #配置upstream upstream my-server { least_conn; # 微服务网关地址 server 192...

    利用 ip + prot 连接websocket服务器,缺点:

        1. 暴露服务器地址和端口;

        2. 只能单节点部署,无法做集群;

        3. 诸多缺点。

    #配置upstream

    upstream my-server {
            least_conn;

            # 微服务网关地址
            server 192.0.1.22:8888 weight=5 max_fails=2 fail_timeout=50;
    }

    #配置server

    server
    {
        listen       80;
        charset utf-8;
        server_name  sokcet.com;
        add_header    Cache-Control  max-age=43200;
        location / {

            # web页面路径配置
            root /home/webdata/test;
            index  index.html index.htm;
        }
        location /test-server {
            root   html;
            index  index.html index.htm;
            proxy_pass http://my-server/test-server;
        }
        location /socket {
            proxy_pass http://192.1.1.20:8081/;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_redirect     off;
            proxy_set_header   Host $host;
            proxy_set_header   X-Real-IP $remote_addr;
            proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header   X-Forwarded-Host $Server_name;
            proxy_connect_timeout 12000s;
            proxy_read_timeout 36000s;
            proxy_send_timeout 36000s;
        }
    }
    配置完后,回到bin目录,重启Nginx:

    nginx -s reload

    域名连接websocket,连接地址:

    ws://socket.com/socket/demo/test

        1. socket.com是上面配置的server_name;

        2. /socket 是location /socket的配置路径;

        3. /demo/test 是websocket服务端接口地址。

    以上配置亲测有效!

    展开全文
  • 用TCP连接分析TUXEDO的WS模式

    千次阅读 2014-07-09 09:59:19
    Abstract: 关于中间件,有一个很有名的定义是:平台+通信。...WS方式使用的是TCP连接,为了对WS方式有更多的了解,我们结合TCP连接的知识对这种方式进行了一个比较深入的分析。 名词说明: WSC: WorkStation Cl

    Abstract: 关于中间件,有一个很有名的定义是:平台+通信。这一点在TUXEDO上面得到了很好的体现,因为它提供了运行和开发的平台,以及多种的通信方式。在这多种通信方式中,使用最频繁的是WS(workstation)方式。WS方式使用的是TCP连接,为了对WS方式有更多的了解,我们结合TCP连接的知识对这种方式进行了一个比较深入的分析。

    名词说明:

    WSC: WorkStation Client               WSL: WorkStation Listener

    WSH: WorkStation Handler            Server: 小写表示服务器端的服务处理进程

     

    TCP连接是一种C/S模式的,即server端公开自己的IP和端口号,client通过这两个参数与之建立连接,客户端使用的端口一般是OS临时分配的。

    TCP server端一般有两种模式,一种是iterative(重复)的,一种concurrent(并发)的。前面一种是一个server的进程(应用层)来处理client的请求,处理完了之后继续接受请求来处理,当server正在处理的过程中,新来的请求得不到处理,只有等待。后面一种是请求到来的时候,server 进程通常会新开一个进程来处理这个请求,自己继续监听公开端口的连接请求。

    在TUXEO这种事务处理系统中,会经常有大量的请求,故第一种模式肯定是不行的,第二种模式虽然可以达到同时处理不同请求的目的,但是由于每次要开新的进程,系统的开销很大,也会影响性能。实际中,TUXEDO的Workstation方式采用了另一种方法来实现多请求的并发处理。下面我们进行详细的说明。

    以下是ubb中关于WSL的配置参数:

    WSL              SRVGRP=Group1 SRVID=200

                         CLOPT="-A -t -- -n //ip(服务器IP,在此隐去):4050 -m 2 -M 10 -x 10"

    其中ip:4050就是TUXEDO服务器的WSL的监听地址,只有一个WSL进程。-m参数指定的是启动时WSH的个数,-M为最大个数(用户数大于m*x时系统会自动启动更多的WSH),-x为每个WSH可以多道处理请求的最大数目,可以理解为WSH的请求缓冲区可以存放十个请求。这样我们上面的配置在启动后可以处理同时20个并发请求,最大可以处理100个。

    根据这个配置和相关参数的解释,我们就可以知道TUXEDO采用的处理模式了,TUXEDO在上面TCP的第二种方式之上进行了改进。监听进程还是只有一个(WSL),但是事先已经起了多个处理请求的进程(WSH),每个WSH又可以处理多个请求,这样就保证了大量的请求能同时得到处理,也省去了临时开服务进程的开销。

    为了很好的理解整个工作过程,我们首先来看一下WSC连上来的时候的一些步骤。


    图1: WSC连接的工作示意图(摘自TUXEDO文档:ADCF04-WS

    http://e-docs.bea.com/tuxedo/tux80/atmi/adwsc4.htm)

     

    上图很清晰的说明了连接的过程。

    这里还需要理解是WSH和server进程之间的关系。因为大家知道,真正处理client请求的是server进程,所有的业务处理,以及和数据库相关的操作都是在server进程中完成的,这也是我们TUXEDO应用开发主要做的部分。我的理解是WSH可以看成是WSC在本地的一个代理。WSH收到WSC的请求数据,放在缓冲区,然后发给server进程来处理,因为在同一台机器上,一般采用本地进程间通信的机制,效率比较高。Server处理完后将结果返回给WSH,WSH再将结果返回给WSC,这个过程中WSH和WSC是保持着TCP连接的,而server进程并不直接和WSC打交道。

           以上的过程也可以参考下图:

    图2: WS方式的连接步骤和相关模块说明图

     

    需要解释的是WSH和server之间的粗线箭头。因为WSH和server直接是多对多的关系,每个WSH可以把请求发给多个server,每个server也可以接受多个WSH发来的请求。

    还有一个问题就是TCP应用是和机器的物理端口绑定的,既然WSL和WSH都要和WSC进行TCP通信,而且很可能是同时的,那么就必须使用不同的端口。这个我们在后面会进行相关的说明。为了简便起见,我将server和WSC都实现在同一台机器上,因为是WS方式,同样会进行TCP连接,和两台机器之前的情况是一样的,但是数据流会采用回环(loopback)设备,但不影响我们对问题的说明。

    结合上面的WSL设置,我们在Windows的任务管理器中看到一个WSL进程和两个WSH进程。

    下面我们结合TCP的知识来说明WS方式中的连接动作。为便于数据的说明,这里给出一个TCP状态的变迁图。限于篇幅,这里不作解释,请大家参考相关的书籍。

                                            

    图3:TCP状态变迁图

     

    下面是在Windows command窗口用netstat看到的输出,并给出相关的解释说明。

    图4:netstat输出1,关于WSC和WSL连接

     

    输出的前面两行是处在TIME_WAIT状态的连接,是之前试验留下的连接,要等到两个MSL(Maximum Segment Lifetime)的时间后结束。

    第三个是当前WSC到WSL的连接,这里地址显示的主机名和端口号。由于WSC和WSL的连接建立时间极短,我们没能看到WSC和WSL连接的ESTABLISHED状态,看到的是进入FIN_WAIT_2状态(从WSC角度)和CLOSE_WAIT状态(从WSL角度)的连接。这个状态表明WSC发起了active close,发送了FIN并收到ACK,但是还没有收到WSL的FIN结束请求,连接处于half-close状态。CLOSE_WAIT表示WSL收到WSC的FIN请求,并发回ACK,与上面的WSC的FIN_WAIT_2状态正好对应。

    在上图的第二个netstat输出中,我们就可以看到使用端口号1544的WSC连接进入到TIME_WAIT状态了,与前面两个连接一样。

     

    图5:netstat输出1,关于WSC和WSH连接

     

    在上面的图4中,我们说明了WSC和WSL的连接。现在我们来看一下WSC和WSH的连接。由于调用的是TOUPPER服务,请求的处理时间极短,所以在图4中没有看到WSC和WSH的连接。为了观察到这个连接,特意在tpinit和tpterm之间加入了一个函数调用sleep(10),让WSC睡眠10s,这样连接就被保持了,在这个过程中,我们用netstat看到了上面的输出。

    大家知道在TCP连接中,一般client使用的端口号都是OS临时分配的,通常是顺序使用的。但是这里除了我们指定的4050端口(WSL)和单调增长的15XX WSC端口外,还有一个3212端口,这个就是WSH使用的端口。笔者经过多次反复的上述试验,发现在ESTABLISHED状态的连接中SERVER端的端口号都是3212和下图中的3213,因而推测这就是我们的两个WSH分别使用的端口。

    从上图,我们分析出的连接过程是,WSC先和WSL建立连接,然后WSC从WSL处得到WSH的端口号,和WSH建立连接,来完成事务处理。由于WSL是唯一的,要被多个WSC使用,所以WSC和WSL的连接是非常短暂的。这与图1中的过程是吻合的,但是我们没有能看到STEP2中WSL和WSH通信的过程。

     

    图6:netstat输出1,关于WSC和WSH连接特性

     

           根据图4和图5,我们详细分析了两个连接的过程。下面我们分析一下图6的输出。

    WSC通过端口1548和WSL建立连接后,很快进入TIME_WAIT,如图6的第一个netstat的第五行(只计TCP行)连接所示。第六行和第七行,WSC用端口1549和WSH(端口3213)建立连接,由于上面提到的sleep(10)而处于ESTABLISHED状态。由于WSC和WSL的连接是要延时关闭的,结合前后输出我们可以确认上述1549端口是被1548端口的WSC使用的。这就是说WSC和WSH建立连接会采用一个新的端口,这是由于TCP的性质决定的。在很多的TCP实现中,处在2MSL等待状态的端口是不能马上被使用的,所以WSC必须使用一个新的端口1549来和WSH连接。

           下面我们来看看另一个有趣的地方。前面说到WSC和WSL的连接很快进入到TIME_WAIT的状态,那么WSC和WSH的连接是否也是这样的呢?从图6的第二个netstat结果中,我们发现不是这样的。因为1549和3213的连接“不见”了,而并没有进入其他TCP状态转换图中的状态。而这时1548的连接还处在TIME_WAIT状态中,表明还没有完成Windows 版TCP/IP实现的2MSL时间。后面的使用1550端口的其它连接也已经建立了,唯独其中的1549连接完全的结束了。这就说明WSC和WSH的连接采用的是结束后立即终止的方法。这样做的好处是可以很快的释放端口,避免client的主机端口被耗尽,特别是在请求发起很多的时候。我们知道主机的端口号在0-65535之间,而且很多是被保留,WSC无法使用的。

           经过上面的分析,相信大家对TUXEDO的WS方式的连接过程有了一个比较清晰的认识。WS方式是实际中使用最多的方式,对这种方式的理解有助于我们的应用开发和对相关系统状况的分析和故障的检查。以上假设大家有相关的TUXEDO开发经验,能完成TOUPPER的WS版的配置和实现即可,另外还要求对TCP协议有相关的了解。希望对大家学习TUXEDO或者网络知识有帮助。对以上的过程还可以进行更细致的分析,例如捕获相关的数据包,监听端口等。这里有一些是我自己的理解,也希望大家批评指正。

     

    后记

    以上是最近在深入学习网络方面的知识,对TCP/IP有了更深的认识和了解之后,结合自己之前在TUXEDO方 面的工作和实践,并做了相关的试验而分析出的一些看法和理解。我觉得这是一个很好的方式:结合正在使用的软件来学习网络的原理,也参考这些原理来理解实际 的过程。而不仅仅是记得那些协议和规定,或者开发只知其然,不知其所以然的应用。协议和软件一样是在不断发展的,借用参考资料中Larry Peterson的一句话就是我们更重要的是要去理解为什么协议要这样实现。

     

     

    参考资料

    1.  TUXEDO  e-docs 官方文档。

    2.  TCP/IP Illustrated V1: The Protocols    W. Richard Stevens

    3.  Computer Networks: A System Approach(2nd) Larry Peterson & Bruce Davie

     

     

        2003.11 HUST, Wuhan
    转自:http://blog.csdn.net/rockyqiu2002/archive/2004/08/21/80859.aspx
    展开全文
  • Websocket如何实现长连接

    千次阅读 2019-12-02 11:30:25
    于是我就想到一个办法,就是自动关闭再重新创建一次(因为自动关闭也不是很快就关闭的,所以我就这么写),虽然实现方式不是很好,但是也暂时的实现了长连接方式 前端JS var websocket = null; var host = ...

    实现长连接

    由于websocket连接成功过段时间自动关闭,无法继续获取消息
    于是我就想到一个办法,就是自动关闭时再重新创建一次(因为自动关闭也不是很快就关闭的,所以我就这么写),虽然实现方式不是很好,但是也暂时的实现了长连接方式
    前端JS

    		var websocket = null;
    		var host = document.location.host;
    		var username = "1001"; // 获得当前登录人员的userName --这里使用当前项目ID做判断
    		var judgeTemp = 0;
    		// alert(username)
    		createWebSorket();
    		function createWebSorket(){
    			//判断当前浏览器是否支持WebSocket 
    			if('WebSocket' in window) {
    				websocket = new WebSocket('ws://' + host + '/Project/webSocket/' + username);
    				initEventHandle();
    			} else {
    				alert('当前浏览器 Not support websocket,消息推送将无法使用')
    			}
    		}
    		function initEventHandle(){
    			//连接发生错误的回调方法 
    			websocket.onerror = function() {
    				judgeTemp = 1;
    				//这里就是你要显示的信息的函数(自定义)
    				setMessageInnerHTML("WebSocket消息推送连接发生错误",1);
    			};
    			
    			//连接成功建立的回调方法 
    			websocket.onopen = function() {
    			//这里就是你要显示的信息的函数(自定义)
    				setMessageInnerHTML("WebSocket消息推送连接成功",1);
    				console.log("成功连接---"+judgeTemp)
    			}
    			
    			//接收到消息的回调方法 
    			websocket.onmessage = function(event) {
    			//这里就是你要显示的信息的函数(自定义)
    				setMessageInnerHTML(event.data);
    			}
    			
    			//连接关闭的回调方法 
    			websocket.onclose = function() {
    				console.log("关闭连接---"+judgeTemp)
    				if(judgeTemp == 1){
    				//这里就是你要显示的信息的函数(自定义)
    					setMessageInnerHTML("WebSocket消息推送连接关闭",1);
    				}else{
    					createWebSorket();
    				}
    			}
    			//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。 
    			window.onbeforeunload = function() {
    				judgeTemp = 1;
    				closeWebSocket();
    			}
    		}
    		//关闭WebSocket连接 
    		function closeWebSocket() {
    			websocket.close();
    		}
    

    struts.xml中配置
    在这里插入图片描述

    <constant name="struts.action.excludePattern" value="/webSocket/.*,ws://.*"></constant>
    

    后端实现
    我这里是用SSH的框架(其实也没啥区别的)

    package com.action;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
     
    import javax.websocket.OnClose;
    import javax.websocket.OnError;
    import javax.websocket.OnMessage;
    import javax.websocket.OnOpen;
    import javax.websocket.Session;
    import javax.websocket.server.PathParam;
    import javax.websocket.server.ServerEndpoint;
     
    import net.sf.json.JSONObject;
    
    @ServerEndpoint("/webSocket/{username}")  
    public class WebSocket { 
            private static int onlineCount = 0; 
           // private static Map<String, WebSocket> clients = new ConcurrentHashMap<String, WebSocket>(); 
            private static List<Map<String, WebSocket>> clients = null;
            private Session session; 
            private String username; 
           
            @OnOpen 
            public void onOpen(@PathParam("username") String username, Session session) throws IOException { 
           
                this.username = username; 
                this.session = session; 
                   
                //为了实现多个页面登录同一个账号时,同时推送全部页面
                if(clients == null) {
                	synchronized (WebSocket.class) {
    					if(clients == null) {
    						clients = new ArrayList<Map<String, WebSocket>>();
    					}
    				}
                }
                addOnlineCount();
                Map<String, WebSocket> clien = new ConcurrentHashMap<String, WebSocket>(); 
                clien.put(username, this);
                clients.add(clien);
                //clients.put(username, this);
                //System.out.println("已连接");
            } 
           
            @OnClose 
            public void onClose() throws IOException { 
            	for(int i=0; i< clients.size(); i++) {
            		Map<String, WebSocket> clien = clients.get(i);
            		for (WebSocket item : clien.values()) { 
            			if(item.session.equals(session))
                			clients.remove(i);
            		}
            	}
                //clients.remove(username); 
                subOnlineCount(); 
            } 
           
            @OnMessage 
            public void onMessage(String message) throws IOException { 
           
                JSONObject jsonTo = JSONObject.fromObject(message); 
                String mes = (String) jsonTo.get("message");
                 
                if (!jsonTo.get("To").equals("All")){ 
                    sendMessageTo(mes, jsonTo.get("To").toString()); 
                }else{ 
                    sendMessageAll(mes); 
                } 
            } 
           
            @OnError 
            public void onError(Session session, Throwable error) { 
                error.printStackTrace(); 
            } 
           
            public void sendMessageTo(String message, String To) throws IOException { 
                // session.getBasicRemote().sendText(message); 
                //session.getAsyncRemote().sendText(message); 
                /*for (WebSocket item : clients.values()) { 
                    if (item.username.equals(To) ) 
                        item.session.getAsyncRemote().sendText(message); 
                } */
            	for(int i=0; i< clients.size(); i++) {
            		Map<String, WebSocket> clien = clients.get(i);
            		for (WebSocket item : clien.values()) { 
            			if (item.username.equals(To) )
            			item.session.getAsyncRemote().sendText(message); 
                    }
            	}
            } 
               
            public void sendMessageAll(String message) throws IOException { 
               /* for (WebSocket item : clients.values()) { 
                    item.session.getAsyncRemote().sendText(message); 
                } */
            	for(int i=0; i< clients.size(); i++) {
            		Map<String, WebSocket> clien = clients.get(i);
            		for (WebSocket item : clien.values()) { 
                        item.session.getAsyncRemote().sendText(message); 
                    }
            	}
            } 
           
            public static synchronized int getOnlineCount() { 
                return onlineCount; 
            } 
           
            public static synchronized void addOnlineCount() { 
                WebSocket.onlineCount++; 
            } 
           
            public static synchronized void subOnlineCount() { 
                WebSocket.onlineCount--; 
            } 
           
            /*public static synchronized Map<String, WebSocket> getClients() { 
                return clients; 
            } */
            public static synchronized List<Map<String, WebSocket>> getClients() { 
                return clients; 
            } 
            
            
            
            
    }
    

    备注
    如果遇到无法找到问题
    通道:https://blog.csdn.net/weixin_43992507/article/details/103256233

    nginx下无法连接websocket
    通道:https://blog.csdn.net/weixin_43992507/article/details/103337106

    SSM和SpringBoot 使用的方式更简单,直接用注解就可以了,不需要在配置文件加什么

    展开全文
  • JavaScript-JS依靠WebSoket也可以像其他语言一样能够实现通信代码,不过使用的时候需要注意检查连接断开的情况。最基本的必须保证IP和端口都可以访问。 目录 WebSocket代码及测试 调用初始化代码 通信示例代码 ...

    JavaScript-JS依靠WebSoket也可以像其他语言一样能够实现通信代码,不过使用的时候需要注意检查连接断开的情况。最基本的必须保证IP和端口都可以访问。

    目录

    WebSocket代码及测试

    调用初始化代码

    通信示例代码

    测试效果

    WebSocket连接关闭重连处理

    连接断开问题

    代码实现重连

    重连效果


    WebSocket代码及测试

    调用初始化代码

     CvNetVideo.Websocket = new WebSocket('ws://' + websocetHost + ":" + websocketPort);
     CvNetVideo.WebsocketCallbackLoader = new WebsocketCallbackLoader();
     CvNetVideo.WebsocketCallbackLoader.connect(CvNetVideo.Websocket);

    通信示例代码

    /*
     * WebsocketCallback Loader
    */
    import JT1078 from '../JX/JTT1078';
    
    class WebsocketCallbackLoader {
    
        constructor() {
            this.websocket = undefined;
            this.onCallback = undefined;
            this.sendMessage = this.sendMessage;
            this.medisPackageAnalysis = new JT1078.MedisPackageAnalysis();
            this.splitData = new JT1078.SplitData();
            this.checkHelper = new JT1078.CheckHelper();
            //分包缓存数据 按SIM做key
            this.AllSimPackData = {};
        }
    
        connect(websocket) {
            this.websocket = websocket;
            this.websocket.onopen = this.openSocket.bind(this);
            this.websocket.onclose = this.closeSocket.bind(this);
            this.websocket.binaryType = 'arraybuffer';
            this.websocket.onmessage = this.receiveSocketMessage.bind(this);
        }
    
        closeSocket(e) {
            console.log('Websocket808 Disconnected!');
        }
    
        openSocket() {
            console.log('Websocket808 Open!');
        }
    
        receiveSocketMessage(event) {
            let data = new Uint8Array(event.data);
            this.splitData.SplitDataBy7E(data, 18, data.byteLength - 18, (bGps) => {
                if (bGps.length > 11 && this.checkHelper.CheckXOR(bGps, 0, bGps.length - 1) === bGps[bGps.length - 1])//效验通过
                {
                    this.JX808DataPD(new Uint8Array(bGps));
                }
            });
        }
        JX808DataPD(bGps) {
            let head = new JT1078.JTHeader();
            head.FillByBinary(bGps, 0);
    
            if (head.PackInfo) {
                var sid = JT1078.GetFirstSerialNumber(head);
                let AllPackData = AllSimPackData[head.Sim];
                if (!AllPackData) {
                    AllPackData = {};
                    AllSimPackData[head.Sim] = AllPackData;
                }
    
                var pd = AllPackData[sid];
                if (pd) {
                    if (!pd.PackData[head.PackInfo.Index]) {
                        pd.PackData.Count += 1;
                    }
                    pd.PackData[head.PackInfo.Index] = JT1078.GetMsbBody(head, bGps);
                    pd.LastRTime = DateTime.Now;
                    if (this.CheckPackByPD(pd))
                        AllPackData[sid] = null;
                }
                else {
                    pd = {};
                    pd.PackData = {};
                    pd.PackData[head.PackInfo.Index] = JT1078.GetMsbBody(head, bGps);
                    pd.PackData.Count = 1;
                    pd.Head = new JT1078.JTHeader(head.MsgId, head.Sub, head.DataEncryptType, head.MsgLen, head.Sim, sid)
                    pd.Head.PackInfo = new JT1078.JTPackageInfo(1, head.PackInfo.Sum);
                    pd.StartTime = pd.LastRTime = DateTime.Now;
                    AllPackData[sid] = pd;
                }
    
            } else {
                this.JX808Data(head, JT1078.GetMsbBody(head, bGps));
            }
        }
        CheckPackByPD(pd) {
            if (pd.PackData.Count === pd.Head.PackInfo.Sum)//判断数据包数和总包数是否相等
            {
                let tmpbuf = new Uint8Array();
                let index = 0;
                for (var i = 0; i < pd.Head.PackInfo.Sum; i++) {
                    tmpbuf.set(pd.PackData[i], index);
                    index += pd.PackData[i].byteLength;
                }
                //解析失败时返回true防止一直解析此错误数据
                try {
                    this.JX808Data(pd.Head, tmpbuf);
                }
                catch (ex)
                {
                    console.error(ex);
                    return true;
                }
                return true;
            }
            return false;
        }
        JX808Data(head, bts) {
            switch (head.MsgId) {
    
                case 0x1205://终端上传音视频资源列表数据格式
                    var videolist = new JT1078.JTVideoListInfo();
                    videolist.FillByBinary(bts, 0);
                    this.onCallback(videolist);
                    break;
                case 0x1206://终端上传FTP完成通知
                    break;
                default:
            }
        }
    
        sendMessage(data, callback) {
            this.onCallback = callback;
            switch (this.websocket.readyState) {
                case 0:
                    console.log("Websocket808 readyState=CONNECTING");
                    break;
                case 1:
                    this.websocket.send(data);
                    break;
                case 2:
                    console.log("Websocket808 readyState=CLOSING");
                    break;
                case 3:
                    console.log("Websocket808 readyState=CLOSED");
                    break;
    
            }
    
        }
    
    }
    
    export default WebsocketCallbackLoader;  

    测试效果

    WebSocket连接关闭重连处理

    连接断开问题

    代码实现重连

    改造一下调用代码和发送消息代码:

       static initWebsocket(websocetHost, websocketPort) {
            CvNetVideo.WebsocketCallbackLoader = new WebsocketCallbackLoader(websocetHost, websocketPort);
            CvNetVideo.WebsocketCallbackLoader.connect();
        }
    /*
     * WebsocketCallback Loader
    */
    import JT1078 from '../JX/JTT1078';
    import { setTimeout } from 'timers';
    
    class WebsocketCallbackLoader {
    
        constructor(host, port) {
            this.host = host;
            this.port = port;
            this.websocket = undefined;
            this.onCallback = undefined;
            this.sendMessage = this.sendMessage;
            this.medisPackageAnalysis = new JT1078.MedisPackageAnalysis();
            this.splitData = new JT1078.SplitData();
            this.checkHelper = new JT1078.CheckHelper();
            //分包缓存数据 按SIM做key
            this.AllSimPackData = {};
        }
    
        connect() {
            var url = "ws://" + this.host + ":" + this.port;
            console.log("Websocket808 WebSocket connect ..." + url);
            this.websocket = new WebSocket(url);
            this.websocket.onopen = this.openSocket.bind(this);
            this.websocket.onclose = this.closeSocket.bind(this);
            this.websocket.binaryType = 'arraybuffer';
            this.websocket.onmessage = this.receiveSocketMessage.bind(this);
        }
    
        closeSocket(e) {
            console.log('Websocket808 Disconnected!');
        }
    
        openSocket() {
            console.log('Websocket808 Open!');
        }
    
        receiveSocketMessage(event) {
            let data = new Uint8Array(event.data);
            this.splitData.SplitDataBy7E(data, 18, data.byteLength - 18, (bGps) => {
                if (bGps.length > 11 && this.checkHelper.CheckXOR(bGps, 0, bGps.length - 1) === bGps[bGps.length - 1])//效验通过
                {
                    this.JX808DataPD(new Uint8Array(bGps));
                }
            });
        }
        JX808DataPD(bGps) {
            let head = new JT1078.JTHeader();
            head.FillByBinary(bGps, 0);
    
            if (head.PackInfo) {
                var sid = JT1078.GetFirstSerialNumber(head);
                let AllPackData = AllSimPackData[head.Sim];
                if (!AllPackData) {
                    AllPackData = {};
                    AllSimPackData[head.Sim] = AllPackData;
                }
    
                var pd = AllPackData[sid];
                if (pd) {
                    if (!pd.PackData[head.PackInfo.Index]) {
                        pd.PackData.Count += 1;
                    }
                    pd.PackData[head.PackInfo.Index] = JT1078.GetMsbBody(head, bGps);
                    pd.LastRTime = DateTime.Now;
                    if (this.CheckPackByPD(pd))
                        AllPackData[sid] = null;
                }
                else {
                    pd = {};
                    pd.PackData = {};
                    pd.PackData[head.PackInfo.Index] = JT1078.GetMsbBody(head, bGps);
                    pd.PackData.Count = 1;
                    pd.Head = new JT1078.JTHeader(head.MsgId, head.Sub, head.DataEncryptType, head.MsgLen, head.Sim, sid)
                    pd.Head.PackInfo = new JT1078.JTPackageInfo(1, head.PackInfo.Sum);
                    pd.StartTime = pd.LastRTime = DateTime.Now;
                    AllPackData[sid] = pd;
                }
    
            } else {
                this.JX808Data(head, JT1078.GetMsbBody(head, bGps));
            }
        }
        CheckPackByPD(pd) {
            if (pd.PackData.Count === pd.Head.PackInfo.Sum)//判断数据包数和总包数是否相等
            {
                let tmpbuf = new Uint8Array();
                let index = 0;
                for (var i = 0; i < pd.Head.PackInfo.Sum; i++) {
                    tmpbuf.set(pd.PackData[i], index);
                    index += pd.PackData[i].byteLength;
                }
                //解析失败时返回true防止一直解析此错误数据
                try {
                    this.JX808Data(pd.Head, tmpbuf);
                }
                catch (ex)
                {
                    console.error(ex);
                    return true;
                }
                return true;
            }
            return false;
        }
        JX808Data(head, bts) {
            switch (head.MsgId) {
    
                case 0x1205://终端上传音视频资源列表数据格式
                    var videolist = new JT1078.JTVideoListInfo();
                    videolist.FillByBinary(bts, 0);
                    this.onCallback(videolist);
                    break;
                case 0x1206://终端上传FTP完成通知
                    break;
                default:
            }
        }
    
        printState() {
            switch (this.websocket.readyState) {
                case 0:
                    console.log("Websocket808 readyState=CONNECTING");
                    break;
                case 1:
                    console.log("Websocket808 readyState=OPEN");
                    break;
                case 2:
                    console.log("Websocket808 readyState=CLOSING");
                    break;
                case 3:
                    console.log("Websocket808 readyState=CLOSED");
                    break;
            }
        }
    
        sendData(data)
        {
            this.websocket.send(data);
        }
    
        sendMessage(data, callback) {
            this.onCallback = callback;
            this.printState();
            if (this.websocket.readyState === 0) {
                setTimeout(() => {
                    this.sendData(data);
                }, 3000);
            } else if (this.websocket.readyState === 2 || this.websocket.readyState === 3) {
                this.connect();
                setTimeout(() => {
                    this.printState();
                    this.sendData(data);
                }, 3000);
            } else {
                this.sendData(data);
            }
    
        }
    
    }
    
    export default WebsocketCallbackLoader;  

    重连效果

     下面是连接断开后重连效果:

    注意:重连是异步调用的,使用setTimeout(func,ms) 调用,因为连接创建需要时间,直接连很有可能正在连接。

    使用队列处理连接失败数据

    /*
     * WebsocketCallback Loader
    */
    import JT1078 from '../JX/JTT1078';
    import Queue from '../utils/queue';
    
    class WebsocketCallbackLoader{
    
        constructor(host, port) {
            this.host = host;
            this.port = port;
            this.websocket = undefined;
            this.medisPackageAnalysis = new JT1078.MedisPackageAnalysis();
            this.splitData = new JT1078.SplitData();
            this.checkHelper = new JT1078.CheckHelper();
            //分包缓存数据 按SIM做key
            this.AllSimPackData = {};
            this.sendCache = new Queue();
            this.onCallback = {};
        }
    
        connect() {
            var url = "ws://" + this.host + ":" + this.port;
            this.websocket = new WebSocket(url);
            this.websocket.onopen = this.openSocket.bind(this);
            this.websocket.onclose = this.closeSocket.bind(this);
            this.websocket.binaryType = 'arraybuffer';
            this.websocket.onmessage = this.receiveSocketMessage.bind(this);
        }
    
        closeSocket(e) {
            console.log('Websocket808 Disconnected!');
        }
    
        openSocket() {
            console.log('Websocket808 Open!');
            while (this.sendCache.size() > 0) {
                this.sendData(this.sendCache.dequeue());
            }
        }
    
        receiveSocketMessage(event) {
            let data = new Uint8Array(event.data);
            this.splitData.SplitDataBy7E(data, 18, data.byteLength - 18, (bGps) => {
                if (bGps.length > 11 && this.checkHelper.CheckXOR(bGps, 0, bGps.length - 1) === bGps[bGps.length - 1])//效验通过
                {
                    this.JX808DataPD(new Uint8Array(bGps));
                }
            });
        }
        JX808DataPD(bGps) {
            let head = new JT1078.JTHeader();
            head.FillByBinary(bGps, 0);
    
            if (head.PackInfo) {
                var sid = JT1078.GetFirstSerialNumber(head);
                let AllPackData = this.AllSimPackData[head.Sim];
                if (!AllPackData) {
                    AllPackData = {};
                    this.AllSimPackData[head.Sim] = AllPackData;
                }
    
                var pd = AllPackData[sid];
                if (pd) {  
                    if (!pd.PackData[head.PackInfo.Index]) {
                        pd.PackData.Count += 1;
                        pd.PackData.totalLength += head.MsgLen;
                    }
                    pd.PackData[head.PackInfo.Index] = JT1078.GetMsbBody(head, bGps);
                    pd.LastRTime = new Date();
                    if (this.CheckPackByPD(pd))
                        AllPackData[sid] = null;
                }
                else {
                    pd = {};
                    pd.PackData = {};
                    pd.PackData[head.PackInfo.Index] = JT1078.GetMsbBody(head, bGps);
                    pd.PackData.Count = 1;
                    pd.PackData.totalLength = head.MsgLen;
                    pd.Head = new JT1078.JTHeader(head.MsgId, head.Sub, head.DataEncryptType, head.MsgLen, head.Sim, sid);
                    pd.Head.PackInfo = new JT1078.JTPackageInfo(1, head.PackInfo.Sum);
                    pd.StartTime = pd.LastRTime = new Date();
                    AllPackData[sid] = pd;
                }
    
            } else {
                this.JX808Data(head, JT1078.GetMsbBody(head, bGps));
            }
        }
        CheckPackByPD(pd) {
            if (pd.PackData.Count === pd.Head.PackInfo.Sum)//判断数据包数和总包数是否相等
            {
                let tmpbuf = new Uint8Array(pd.PackData.totalLength);
                let index = 0;
                for (var i = 1; i <= pd.Head.PackInfo.Sum; i++) {
                    tmpbuf.set(pd.PackData[i], index);
                    index += pd.PackData[i].byteLength;
                }
                //解析失败时返回true防止一直解析此错误数据
                try {
                    this.JX808Data(pd.Head, tmpbuf);
                }
                catch (ex) {
                    console.error(ex);
                    return true;
                }
                return true;
            }
            return false;
        }
        JX808Data(head, bts) {
            switch (head.MsgId) {
    
                case 0x1205://终端上传音视频资源列表数据格式
                    var videolist = new JT1078.JTVideoListInfo();
                    videolist.FillByBinary(bts, 0);
                    this.onCallback[0x1205](videolist);
                    break;
                case 0x1206://终端上传FTP完成通知
                    var fileUploadEndInform = new JT1078.JTVideoFileUploadEndInform();
                    fileUploadEndInform.FillByBinary(bts, 0);
                    this.onCallback[0x1206](fileUploadEndInform);
                    break;
                default:
            }
        }
    
        printState() {
            switch (this.websocket.readyState) {
                case 0:
                    console.log("Websocket808 readyState=CONNECTING");
                    break;
                case 1:
                    console.log("Websocket808 readyState=OPEN");
                    break;
                case 2:
                    console.log("Websocket808 readyState=CLOSING");
                    break;
                case 3:
                    console.log("Websocket808 readyState=CLOSED");
                    break;
            }
        }
    
        sendData(data)
        {
            this.websocket.send(data);
        }
    
        sendMessage(data, callback, id) {
    
            this.onCallback[id] = callback;
            if (this.websocket.readyState === 0) {
                this.sendCache.enqueue(data);
            } else if (this.websocket.readyState === 2 || this.websocket.readyState === 3) {
                this.printState();
                this.sendCache.enqueue(data);
                this.connect();
            } else {
                this.sendData(data);
            }
    
        }
    
    }
    
    export default WebsocketCallbackLoader;  

     

    展开全文
  • Python WebSocket长连接心跳与短连接

    千次阅读 2018-08-16 15:51:00
    python websocket 安装 pip install websocket-client ...先来看一下,长连接调用方式: ws = websocket.WebSocketApp("ws://echo.websocket.org/", on_message = on_message, ...
  • SignalR长连接的简单用法

    千次阅读 2019-08-08 11:01:20
    实时 Web 功能是指这样一种功能:当所连接的客户端变得可用服务器代码可以立即向其推送内容,而不是让服务器等待客户端请求新的数据。 下面是简单的demo;参考...
  • 数据库“长连接”与“短连接

    万次阅读 2012-04-16 15:27:02
    什么是长连接? 其实长连接是相对于通常的短连接而说的,也就是时间保持...这就要求长连接在没有数据通信,定时发送数据包,以维持连接状态,短连接在没有数据传输直接关闭就行了 什么时候用长连接,短连接
  • android websocket长连接推送

    千次阅读 2015-04-03 17:09:27
    android利用autobahn和服务器端websocket长连接以用来推送 经测试可以运行成功,实现服务器,android间相互通信
  • 客户端与服务端长连接的几种方式

    千次阅读 2019-12-05 16:51:51
    在日常 Web 项目中,通常使用的是短连接。即一个 Request 对应一个 Response,发起请求后建立TCP...但是对于股票信息更新、即时通讯、在线游戏这种数据交互频繁的场景就需要使用长连接。今天记录一下长连接的几种方式。
  • websocket 实现长连接原理

    万次阅读 多人点赞 2019-02-21 21:18:24
    一、WebSocket是HTML5出的东西(协议),也就是说HTTP协议没有变化,或者说没关系,但HTTP是不支持持久连接的(长连接,循环连接的不算)首先HTTP有1.1和1.0之说,也就是所谓的keep-alive,把多个HTTP请求合并为一个...
  • 什么是长连接? 其实长连接是相对于通常的短连接而说的,也...这就要求长连接在没有数据通信,定时发送数据包,以维持连接状态,短连接在没有数据传输直接关闭就行了 什么时候用长连接,短连接长连接主要用于...
  • 在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。 很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的...
  • 安卓websocket长连接

    千次阅读 2017-06-29 00:12:41
    简介WebSocket协议是一种建立在TCP连接基础上的全双工通信的协议。 全双工就是指客户端和服务端可以同时进行双向通信,强调同时、双向通信. 关于WebSocket协议,一般来说,如果是通过https协议开始升级而来的,...
  • websocket长连接

    千次阅读 2018-01-25 10:31:44
     * 连接关闭时wsSet删除,并且连接数-1  */  @OnClose  public void onClose () {  wsSet.remove(this); //删除  subOnlineCount(); // 在线人数-1  }  /**  * websocket错误的时候丢出一...
  • Nginx代理webSocket60s自动断开, 怎么保持长连接

    万次阅读 多人点赞 2018-04-14 17:49:46
    利用nginx代理websocket的时候,发现客户端和服务器握手成功后,如果在60s时间内没有数据交互,连接就会自动断开,如下图:为了保持长连接,可以采取来两种方式.1.nginx.conf 文件里location 中的proxy_read_time...
  • golang Gin建立长连接web socket

    千次阅读 2019-07-02 17:58:52
    //连接打开触发 ws.onopen = function(evt) { console.log("Connection open ..."); ws.send("Hello WebSockets!"); }; //接收到消息触发 ws.onmessage = function(evt) { console.log("Received ...
  • java WebsocketClient 客户端 长连接机制

    千次阅读 2019-08-10 18:04:01
    private static String Ws = "ws://192.168.1.127:88/art/3333"; private static String Url = “ http://192.168.1.127:88/art/ ”; public static void listenSocekt() { // netSock 先测网络是否同 flag =...
  • Lua websocket长连接

    千次阅读 2020-10-27 14:05:30
    --建立新连接 local wb, err = server:new{ timeout = 5000, -- in milliseconds max_payload_len = 65535, } if not wb then ngx.log(ngx.ERR, "failed to new websocket: ", err) return ngx.exit(4
  • 数据库中的长连接和短连接区别分析
  • Golang长连接-基于WebSocket

    千次阅读 2020-06-15 15:08:02
    Websocket简介 WebSocket可以实现客户端与服务器间双向、基于消息的文本或二进制数据传输。它是浏览器中最靠近套接...WebSocket资源URL采用了自定义模式:ws表示纯文本通信(如ws://example.com/socket),wss表示使用
  • 因为Nginx默认的断开链接时间为60秒,为保持长连接,可有两种解决方法。 一、配置Nginx,设置读超时时间大一点,如下图 按照上述方法设置好后,我们可以发现,如果在10分钟之内没有数据交互的话,websocket连接...
  • HTTP的长连接和短连接本质上是TCP长连接和短连接。...IP协议主要解决网络路由和寻址问题,TCP协议主要解决如何在IP层之上可靠的传递数据包,使在网络上的另一端收到发端...长连接连接操作过程 短连接的操作步骤是:
  • C++服务端长连接实现

    2018-05-23 10:17:00
    在网上找了很多Socket长连接的实现方式,但是自己拿过来用都有问题,为了解决这个问题,本人花了不少时间在上面。其实 socket 长连接很简单,就是连接后不断开即可。接下来,这里贴上实现的源码例子。本人做这个...
  • Spring Cloud Gateway 管理 Netty 长连接

    万次阅读 2020-04-10 01:50:39
    当我们开放一个Netty服务端端口,一定会出现这样的问题,“对外开放了Netty端口,所以所有的人都可以通过我的长连接端口请求”,这样的话长连接端口就会极度不安全。所以这篇文章讲述一下,如何通过网关来过滤...
  • Websocket 突破最大长连接

    千次阅读 2019-12-23 18:08:27
    为了测试机器能够最大的长连接个数,故写了一个js脚本,需要用node进行执行 var WebSocketClient = require('websocket').client; var size = 8000; var index = 0; setInterval(function () { if (index < ...
  • Node.js websocket/ws 详解

    万次阅读 2018-08-20 00:21:25
    对nodejs的websocket/ws模块的一个解析

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 30,949
精华内容 12,379
关键字:

ws连接时长