欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

WebSocket原理及技术

程序员文章站 2022-05-21 09:30:05
...

WebSocket原理及技术简介

Siwind原创,转载请注明。

 

WebSocket用于在Web浏览器和服务器之间进行任意的双向数据传输的一种技术。WebSocket协议基于TCP协议实现,包含初始的握手过程,以及后续的多次数据帧双向传输过程。其目的是在WebSocket应用和WebSocket服务器进行频繁双向通信时,可以使服务器避免打开多个HTTP连接进行工作来节约资源,提高了工作效率和资源利用率。

1. 引言

互联网发展的早期,网站上只是一些静态展示页面。用户请求(Request)网站页面,网站回复(Response)页面内容给用户浏览器。因为需求简单,所以也没有很复杂的协议过程。这种形式的Request/Response交互流程如下图所示:

WebSocket原理及技术

11 Request/Response

 

    随着互联网技术的发展,带宽逐步提高,用户数也越来越庞大。对互联网的呈现内容提出了要求,随之出现了动态页面技术,对同一个页面,页面的某些部分对不同的访问用户,呈现的内容不同。相关的实现技术有CGI、ASP、PHP、JSP等。由于访问量的增加,WEB服务器同时处理的用户数也达到了万(10K)以上级别,这就是C10K问题:”The C10K problem[1]。为了缓解服务器压力,每次Request/Response后连接(TCP连接)继续保持,以及对同一个TCP连接,多次复用Request/Response的方法(也称为Pipeline)也提了出来。这就是HTTP/1.1协议中长连接的主要内容。

    伴随移动互联网的发展,大量移动终端和其上的APP应用接入网络,HTML5技术也提了出来,以便支持WEB上的音视频播放、实时游戏、实时聊天等。催生了这样一个需求,当服务器有更新时,需要立即将数据发送给客户端,这就是基于服务器端的推送技术。

    WEBSOCKET之前的解决方法大概这么几种: 1)轮询:客户端设置一个时间间隔,时间到以后,向服务器发送request询问有无新数据,服务器立即返回response,如果有更新则携带更新的数据。2)长连接(long poll): 和轮询相似,但是为阻塞模式的轮询,客户端请求新的数据request, 服务器会阻塞请求,直到有新数据后才返回response给客户端;然后客户端再重复此过程。这两种方式的特点,不断的建立HTTP连接,然后发送请求request,之后服务器等待处理。服务端体现的是一种被动性,同时这种处理方式,非常耗费网络带宽和服务器资源。

    服务器向客户端推送更新时,因为被动性,对低延迟的应用体验不好;因为request/response的交互方式,对网络带宽和服务器带来了额外的负担(例如多次请求的HTTP头部, TCP连接复用会导致的Head-of-Line Blocking线头阻塞[2]等)。如果在单一的TCP连接中,使用双向通信(全双工通信)就能很好的解决此问题。这就是WebSocket技术的缘由。

 

2. WebSocket技术及协议

WebSocket技术的优点有:1)通过第一次HTTP Request建立了连接之后,后续的数据交换都不用再重新发送HTTP Request,节省了带宽资源; 2) WebSocket的连接是双向通信的连接,在同一个TCP连接上,既可以发送,也可以接收; 3)具有多路复用的功能(multiplexing),也即几个不同的URI可以复用同一个WebSocket连接。这些特点非常类似TCP连接,但是因为它借用了HTTP协议的一些概念,所以被称为了WebSocket。

2.1 WebSocket API

WebSocket API[3], 也称为WebSocket接口(Interface),定义了Web应用和服务器进行双向通信的公共接口。 如下图所示:

WebSocket原理及技术

21 WebSocket API

接口的内容可以分为三类:状态变量、网络功能和消息处理等

  1. 构造函数WebSocket(url, protocols):构造WebSocket对象,以及建立和服务器连接; protocols可选字段,代表选择的子协议

  2. 状态变量readyState: 代表当前连接的状态,短整型数据,取值为CONNECTING(值为0), OPEN(值为1), CLOSING(值为2), CLOSED(值为3)

  3. 方法变量close(code, reason): 关闭此WebSocket连接。

  4. 状态变量bufferedAmount: send函数调用后,被缓存并且未发送到网络上的数据长度

  5. 方法变量send(data): 将数据data通过此WebSocket发送到对端

  6. 回调函数onopen/onmessage/onerror/onclose: 当相应的事件发生时会触发此回调函数

 2.1.1 示例

客户端使用例子(JavaScript):

 

[javascript] view plain copy
print?
  1. var websocket = new WebSocket(“ws://www.host.com/path”);   
  2. websocket.onopen = function(evt) { onOpen(evt) };   
  3. websocket.onclose = function(evt) { onClose(evt) };   
  4. websocket.onmessage = function(evt) { onMessage(evt) };   
  5. websocket.onerror = function(evt) { onError(evt) }; }    
  6. function onMessage(evt) { alert( evt.data); }  
  7. function onError(evt) { alert( evt.data); }    
  8. websocket.send(”client to server”);  
var websocket = new WebSocket("ws://www.host.com/path"); 
websocket.onopen = function(evt) { onOpen(evt) }; 
websocket.onclose = function(evt) { onClose(evt) }; 
websocket.onmessage = function(evt) { onMessage(evt) }; 
websocket.onerror = function(evt) { onError(evt) }; }  
function onMessage(evt) { alert( evt.data); }
function onError(evt) { alert( evt.data); }  
websocket.send("client to server");

 2.2 WebSocket协议

WebSocket看成是一种类似TCP/IP的socket技术;此socket在Web应用中实现,并获得了和TCP/IP通信一样灵活方便的全双向通信功能。

WebSocket协议由RFC 6455定义。协议分为两个部分: 握手阶段和数据通信阶段。

WebSocket为应用层协议,其定义在TCP/IP协议栈之上。WebSocket连接服务器的URI以“ws”或者“wss”开头。ws开头的默认TCP端口为80,wss开头的默认端口为443。

 2.2.1 握手阶段

客户端和服务器建立TCP连接之后,客户端发送握手请求,随后服务器发送握手响应即完成握手阶段。如下图所示:

WebSocket原理及技术

22 Handshake

  • 客户端握手请求类似如下:

WebSocket原理及技术


  • 服务器的握手响应类似如下:

WebSocket原理及技术

 

需要关闭连接时,任意一方直接发送类型为关闭帧(Close frame)的控制帧数据给对方即可。

 2.2.2 数据通信

WebSocket的数据在发送时,被组织为依次序的一串数据帧(data frame),然后进行传送。

传送的帧类型分为两类:数据帧(data frame)和控制帧(Control frame)。数据帧可以携带文本数据或者二进制数据;控制帧包含关闭帧(Close frame)和Ping/Pong帧。

帧的格式如下所示:

WebSocket原理及技术

其中最重要的字段为opcode(4bit)和MASK(1bit):

MASK值,从客户端进行发送的帧必须置此位为1,从服务器发送的帧必须置为0。如果任何一方收到的帧不符合此要求,则发送关闭帧(Close frame)关闭连接。

  • opcode的值: 0x1代表此帧为文本数据帧, 0x2代表此帧为二进制数据帧, 0x8为控制帧中的连接关闭帧(close frame), 0x9为控制帧中的Ping帧, 0xA(十进制的10)为控制帧中的Pong帧。

    Ping/Pong帧: Ping帧和Pong帧用于连接的保活(keepalive)或者诊断对端是否在线。这两种帧的发送和接收不对WEB应用公开接口,由实现WebSocket协议的底层应用(例如浏览器)来实现它。

     2.2.3 连接关闭

    任何一端发送关闭帧给对方,即可关闭连接。关闭连接时通常都带有关闭连接的状态码(status code)。常见状态码的含义如下:

    1000 连接正常关闭

  • 1001 端点离线,例如服务器down,或者浏览器已经离开此页面

  • 1002 端点因为协议错误而中断连接

  • 1003 端点因为受到不能接受的数据类型而中断连接

  • 1004 保留

  • 1005 保留, 用于提示应用未收到连接关闭的状态码

  • 1006 端点异常关闭

  • 1007 端点收到的数据帧类型不一致而导致连接关闭

  • 1008 数据违例而关闭连接

  • 1009 收到的消息数据太大而关闭连接

  • 1010 客户端因为服务器未协商扩展而关闭

  • 1011 服务器因为遭遇异常而关闭连接

  • 1015 TLS握手失败关闭连接

     3. WebSocket示例

    这里以JAVA+Eclipse+TOMCAT+JDK8+浏览器,做为例子。

    具体代码github链接:https://github.com/siwind/HelloWebJava

    以回声服务器为例,打开Eclipse,新建Web – Dynamic Web Project项目,项目名称”HelloWebJava”

     3.1 WebSocket服务端

    在项目中新建java类,采用注解的方式,实现OnOpen/OnClose/OnMessage回调方法即可。代码如下:

     

    1. import java.io.IOException;  
    2.   
    3. import javax.websocket.*;  
    4. import javax.websocket.server.ServerEndpoint;  
    5.   
    6.   
    7. @ServerEndpoint(“/WSHello”)  
    8. public class HelloEndPoint {  
    9.   
    10.     @OnOpen  
    11.     public void onOpen(Session session){  
    12.         System.out.println(”Session ” + session.getId() + “ has opened a connection”);   
    13.         try {  
    14.             session.getBasicRemote().sendText(”Connection Established”);  
    15.         } catch (IOException ex) {  
    16.             ex.printStackTrace();  
    17.         }  
    18.     }  
    19.    
    20.   
    21.     @OnMessage  
    22.     public void onMessage(String message, Session session){  
    23.         System.out.println(”Message from ” + session.getId() + “: ” + message);  
    24.          
    25.         try {  
    26.             session.getBasicRemote().sendText(message);  
    27.         } catch (IOException ex) {  
    28.             ex.printStackTrace();  
    29.         }  
    30.     }  
    31.    
    32.   
    33.     @OnClose  
    34.     public void onClose(Session session){  
    35.         System.out.println(”Session ” +session.getId()+“ has closed!”);  
    36.     }  
    37.       
    38.     /** 
    39.      * 注意: OnError() 只能出现一次.   其中的参数都是可选的。 
    40.      * @param session 
    41.      * @param t 
    42.      */  
    43.     @OnError  
    44.     public void onError(Session session, Throwable t) {  
    45.         t.printStackTrace();  
    46.     }  
    47.       
    48. }  
    import java.io.IOException;
    
    import javax.websocket.*;
    import javax.websocket.server.ServerEndpoint;
    
    
    @ServerEndpoint("/WSHello")
    public class HelloEndPoint {
    
        @OnOpen
        public void onOpen(Session session){
            System.out.println("Session " + session.getId() + " has opened a connection"); 
            try {
                session.getBasicRemote().sendText("Connection Established");
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    
    
        @OnMessage
        public void onMessage(String message, Session session){
            System.out.println("Message from " + session.getId() + ": " + message);
    
            try {
                session.getBasicRemote().sendText(message);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    
    
        @OnClose
        public void onClose(Session session){
            System.out.println("Session " +session.getId()+" has closed!");
        }
    
        /**
         * 注意: OnError() 只能出现一次.   其中的参数都是可选的。
         * @param session
         * @param t
         */
        @OnError
        public void onError(Session session, Throwable t) {
            t.printStackTrace();
        }
    
    }


    3.2 WebSocket浏览器客户端

    在项目的WebContent目录下面,新建名称为index.htm的文件,内容如下(部分):

    [javascript] view plain copy
    print?
    1. webSocket = new WebSocket(wsUri);  
    2. webSocket.onopen =function(event){  
    3. if(event.data === undefined)  
    4. return;  
    5.    
    6. writeResponse(event.data);  
    7. };  
    8.    
    9. webSocket.onmessage =function(event){  
    10. writeResponse(event.data);  
    11. };  
    12.    
    13. webSocket.onerror =function(event){  
    14. writeResponse(”<span style=’color: red;’>ERROR: </span>Connection error! ” + event.data);  
    15. };  
    16. webSocket.onclose =function(event){  
    17. writeResponse(”<span style=’color: blue;’>INFO: </span>Connection closed. code=” + event.code);  
    18. };  
    19. }  
    webSocket = new WebSocket(wsUri);
    webSocket.onopen =function(event){
    if(event.data === undefined)
    return;
    
    writeResponse(event.data);
    };
    
    webSocket.onmessage =function(event){
    writeResponse(event.data);
    };
    
    webSocket.onerror =function(event){
    writeResponse("<span style='color: red;'>ERROR: </span>Connection error! " + event.data);
    };
    webSocket.onclose =function(event){
    writeResponse("<span style='color: blue;'>INFO: </span>Connection closed. code=" + event.code);
    };
    }

    3.3 部署及运行

    在JDK8环境下,部署到Tomcat8.0.x/Tomcat8.5.x/Wildfly10.x/Glassfish4.x,正常运行。如下图所示:

     

    WebSocket原理及技术

    31 WebSocket Echo Example

    4.  结论

    WebSocket和传统的HTTP交互方式的区别如下图:

    WebSocket原理及技术

    41交互方式比较

     

    WebSocket的结论如下:

    • 基于TCP/IP协议实现

    • 是一种全双向的通信, 具有底层socket的特点

    • 节约带宽,节省服务器资源

    • 是HTML5的技术之一,具有巨大的应用前景

     

    本文的完整示例代码: https://github.com/siwind/HelloWebJava

     

     

    参考文献

     

    [1] Dan Kegel. The C10K problem[EB/OL]. http://www.kegel.com/c10k.html.

    [2] Head-of-line blocking[EB/OL]. https://en.wikipedia.org/wiki/Head-of-line_blocking.

    [3] W3C Candidate Recommendation 20 September 2012. The WebSocket API[EB/OL]. https://www.w3.org/TR/websockets/.

     

  • WebSocket原理及技术简介

    Siwind原创,转载请注明。

     

    WebSocket用于在Web浏览器和服务器之间进行任意的双向数据传输的一种技术。WebSocket协议基于TCP协议实现,包含初始的握手过程,以及后续的多次数据帧双向传输过程。其目的是在WebSocket应用和WebSocket服务器进行频繁双向通信时,可以使服务器避免打开多个HTTP连接进行工作来节约资源,提高了工作效率和资源利用率。

    1. 引言

    互联网发展的早期,网站上只是一些静态展示页面。用户请求(Request)网站页面,网站回复(Response)页面内容给用户浏览器。因为需求简单,所以也没有很复杂的协议过程。这种形式的Request/Response交互流程如下图所示:

    WebSocket原理及技术

    11 Request/Response

     

        随着互联网技术的发展,带宽逐步提高,用户数也越来越庞大。对互联网的呈现内容提出了要求,随之出现了动态页面技术,对同一个页面,页面的某些部分对不同的访问用户,呈现的内容不同。相关的实现技术有CGI、ASP、PHP、JSP等。由于访问量的增加,WEB服务器同时处理的用户数也达到了万(10K)以上级别,这就是C10K问题:”The C10K problem[1]。为了缓解服务器压力,每次Request/Response后连接(TCP连接)继续保持,以及对同一个TCP连接,多次复用Request/Response的方法(也称为Pipeline)也提了出来。这就是HTTP/1.1协议中长连接的主要内容。

        伴随移动互联网的发展,大量移动终端和其上的APP应用接入网络,HTML5技术也提了出来,以便支持WEB上的音视频播放、实时游戏、实时聊天等。催生了这样一个需求,当服务器有更新时,需要立即将数据发送给客户端,这就是基于服务器端的推送技术。

        WEBSOCKET之前的解决方法大概这么几种: 1)轮询:客户端设置一个时间间隔,时间到以后,向服务器发送request询问有无新数据,服务器立即返回response,如果有更新则携带更新的数据。2)长连接(long poll): 和轮询相似,但是为阻塞模式的轮询,客户端请求新的数据request, 服务器会阻塞请求,直到有新数据后才返回response给客户端;然后客户端再重复此过程。这两种方式的特点,不断的建立HTTP连接,然后发送请求request,之后服务器等待处理。服务端体现的是一种被动性,同时这种处理方式,非常耗费网络带宽和服务器资源。

        服务器向客户端推送更新时,因为被动性,对低延迟的应用体验不好;因为request/response的交互方式,对网络带宽和服务器带来了额外的负担(例如多次请求的HTTP头部, TCP连接复用会导致的Head-of-Line Blocking线头阻塞[2]等)。如果在单一的TCP连接中,使用双向通信(全双工通信)就能很好的解决此问题。这就是WebSocket技术的缘由。

     

    2. WebSocket技术及协议

    WebSocket技术的优点有:1)通过第一次HTTP Request建立了连接之后,后续的数据交换都不用再重新发送HTTP Request,节省了带宽资源; 2) WebSocket的连接是双向通信的连接,在同一个TCP连接上,既可以发送,也可以接收; 3)具有多路复用的功能(multiplexing),也即几个不同的URI可以复用同一个WebSocket连接。这些特点非常类似TCP连接,但是因为它借用了HTTP协议的一些概念,所以被称为了WebSocket。

    2.1 WebSocket API

    WebSocket API[3], 也称为WebSocket接口(Interface),定义了Web应用和服务器进行双向通信的公共接口。 如下图所示:

    WebSocket原理及技术

    21 WebSocket API

    接口的内容可以分为三类:状态变量、网络功能和消息处理等

    1. 构造函数WebSocket(url, protocols):构造WebSocket对象,以及建立和服务器连接; protocols可选字段,代表选择的子协议

    2. 状态变量readyState: 代表当前连接的状态,短整型数据,取值为CONNECTING(值为0), OPEN(值为1), CLOSING(值为2), CLOSED(值为3)

    3. 方法变量close(code, reason): 关闭此WebSocket连接。

    4. 状态变量bufferedAmount: send函数调用后,被缓存并且未发送到网络上的数据长度

    5. 方法变量send(data): 将数据data通过此WebSocket发送到对端

    6. 回调函数onopen/onmessage/onerror/onclose: 当相应的事件发生时会触发此回调函数

     2.1.1 示例

    客户端使用例子(JavaScript):

     

    [javascript] view plain copy
    print?
    1. var websocket = new WebSocket(“ws://www.host.com/path”);   
    2. websocket.onopen = function(evt) { onOpen(evt) };   
    3. websocket.onclose = function(evt) { onClose(evt) };   
    4. websocket.onmessage = function(evt) { onMessage(evt) };   
    5. websocket.onerror = function(evt) { onError(evt) }; }    
    6. function onMessage(evt) { alert( evt.data); }  
    7. function onError(evt) { alert( evt.data); }    
    8. websocket.send(”client to server”);  
    var websocket = new WebSocket("ws://www.host.com/path"); 
    websocket.onopen = function(evt) { onOpen(evt) }; 
    websocket.onclose = function(evt) { onClose(evt) }; 
    websocket.onmessage = function(evt) { onMessage(evt) }; 
    websocket.onerror = function(evt) { onError(evt) }; }  
    function onMessage(evt) { alert( evt.data); }
    function onError(evt) { alert( evt.data); }  
    websocket.send("client to server");
    

     2.2 WebSocket协议

    WebSocket看成是一种类似TCP/IP的socket技术;此socket在Web应用中实现,并获得了和TCP/IP通信一样灵活方便的全双向通信功能。

    WebSocket协议由RFC 6455定义。协议分为两个部分: 握手阶段和数据通信阶段。

    WebSocket为应用层协议,其定义在TCP/IP协议栈之上。WebSocket连接服务器的URI以“ws”或者“wss”开头。ws开头的默认TCP端口为80,wss开头的默认端口为443。

     2.2.1 握手阶段

    客户端和服务器建立TCP连接之后,客户端发送握手请求,随后服务器发送握手响应即完成握手阶段。如下图所示:

    WebSocket原理及技术

    22 Handshake

    • 客户端握手请求类似如下:

    WebSocket原理及技术


    • 服务器的握手响应类似如下:

    WebSocket原理及技术

     

    需要关闭连接时,任意一方直接发送类型为关闭帧(Close frame)的控制帧数据给对方即可。

     2.2.2 数据通信

    WebSocket的数据在发送时,被组织为依次序的一串数据帧(data frame),然后进行传送。

    传送的帧类型分为两类:数据帧(data frame)和控制帧(Control frame)。数据帧可以携带文本数据或者二进制数据;控制帧包含关闭帧(Close frame)和Ping/Pong帧。

    帧的格式如下所示:

    WebSocket原理及技术

    其中最重要的字段为opcode(4bit)和MASK(1bit):

    MASK值,从客户端进行发送的帧必须置此位为1,从服务器发送的帧必须置为0。如果任何一方收到的帧不符合此要求,则发送关闭帧(Close frame)关闭连接。

  • opcode的值: 0x1代表此帧为文本数据帧, 0x2代表此帧为二进制数据帧, 0x8为控制帧中的连接关闭帧(close frame), 0x9为控制帧中的Ping帧, 0xA(十进制的10)为控制帧中的Pong帧。

    Ping/Pong帧: Ping帧和Pong帧用于连接的保活(keepalive)或者诊断对端是否在线。这两种帧的发送和接收不对WEB应用公开接口,由实现WebSocket协议的底层应用(例如浏览器)来实现它。

     2.2.3 连接关闭

    任何一端发送关闭帧给对方,即可关闭连接。关闭连接时通常都带有关闭连接的状态码(status code)。常见状态码的含义如下:

    1000 连接正常关闭

  • 1001 端点离线,例如服务器down,或者浏览器已经离开此页面

  • 1002 端点因为协议错误而中断连接

  • 1003 端点因为受到不能接受的数据类型而中断连接

  • 1004 保留

  • 1005 保留, 用于提示应用未收到连接关闭的状态码

  • 1006 端点异常关闭

  • 1007 端点收到的数据帧类型不一致而导致连接关闭

  • 1008 数据违例而关闭连接

  • 1009 收到的消息数据太大而关闭连接

  • 1010 客户端因为服务器未协商扩展而关闭

  • 1011 服务器因为遭遇异常而关闭连接

  • 1015 TLS握手失败关闭连接

     3. WebSocket示例

    这里以JAVA+Eclipse+TOMCAT+JDK8+浏览器,做为例子。

    具体代码github链接:https://github.com/siwind/HelloWebJava

    以回声服务器为例,打开Eclipse,新建Web – Dynamic Web Project项目,项目名称”HelloWebJava”

     3.1 WebSocket服务端

    在项目中新建java类,采用注解的方式,实现OnOpen/OnClose/OnMessage回调方法即可。代码如下:

     

    1. import java.io.IOException;  
    2.   
    3. import javax.websocket.*;  
    4. import javax.websocket.server.ServerEndpoint;  
    5.   
    6.   
    7. @ServerEndpoint(“/WSHello”)  
    8. public class HelloEndPoint {  
    9.   
    10.     @OnOpen  
    11.     public void onOpen(Session session){  
    12.         System.out.println(”Session ” + session.getId() + “ has opened a connection”);   
    13.         try {  
    14.             session.getBasicRemote().sendText(”Connection Established”);  
    15.         } catch (IOException ex) {  
    16.             ex.printStackTrace();  
    17.         }  
    18.     }  
    19.    
    20.   
    21.     @OnMessage  
    22.     public void onMessage(String message, Session session){  
    23.         System.out.println(”Message from ” + session.getId() + “: ” + message);  
    24.          
    25.         try {  
    26.             session.getBasicRemote().sendText(message);  
    27.         } catch (IOException ex) {  
    28.             ex.printStackTrace();  
    29.         }  
    30.     }  
    31.    
    32.   
    33.     @OnClose  
    34.     public void onClose(Session session){  
    35.         System.out.println(”Session ” +session.getId()+“ has closed!”);  
    36.     }  
    37.       
    38.     /** 
    39.      * 注意: OnError() 只能出现一次.   其中的参数都是可选的。 
    40.      * @param session 
    41.      * @param t 
    42.      */  
    43.     @OnError  
    44.     public void onError(Session session, Throwable t) {  
    45.         t.printStackTrace();  
    46.     }  
    47.       
    48. }  
    import java.io.IOException;
    
    import javax.websocket.*;
    import javax.websocket.server.ServerEndpoint;
    
    
    @ServerEndpoint("/WSHello")
    public class HelloEndPoint {
    
        @OnOpen
        public void onOpen(Session session){
            System.out.println("Session " + session.getId() + " has opened a connection"); 
            try {
                session.getBasicRemote().sendText("Connection Established");
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    
    
        @OnMessage
        public void onMessage(String message, Session session){
            System.out.println("Message from " + session.getId() + ": " + message);
    
            try {
                session.getBasicRemote().sendText(message);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    
    
        @OnClose
        public void onClose(Session session){
            System.out.println("Session " +session.getId()+" has closed!");
        }
    
        /**
         * 注意: OnError() 只能出现一次.   其中的参数都是可选的。
         * @param session
         * @param t
         */
        @OnError
        public void onError(Session session, Throwable t) {
            t.printStackTrace();
        }
    
    }


    3.2 WebSocket浏览器客户端

    在项目的WebContent目录下面,新建名称为index.htm的文件,内容如下(部分):

    [javascript] view plain copy
    print?
    1. webSocket = new WebSocket(wsUri);  
    2. webSocket.onopen =function(event){  
    3. if(event.data === undefined)  
    4. return;  
    5.    
    6. writeResponse(event.data);  
    7. };  
    8.    
    9. webSocket.onmessage =function(event){  
    10. writeResponse(event.data);  
    11. };  
    12.    
    13. webSocket.onerror =function(event){  
    14. writeResponse(”<span style=’color: red;’>ERROR: </span>Connection error! ” + event.data);  
    15. };  
    16. webSocket.onclose =function(event){  
    17. writeResponse(”<span style=’color: blue;’>INFO: </span>Connection closed. code=” + event.code);  
    18. };  
    19. }  
    webSocket = new WebSocket(wsUri);
    webSocket.onopen =function(event){
    if(event.data === undefined)
    return;
    
    writeResponse(event.data);
    };
    
    webSocket.onmessage =function(event){
    writeResponse(event.data);
    };
    
    webSocket.onerror =function(event){
    writeResponse("<span style='color: red;'>ERROR: </span>Connection error! " + event.data);
    };
    webSocket.onclose =function(event){
    writeResponse("<span style='color: blue;'>INFO: </span>Connection closed. code=" + event.code);
    };
    }

    3.3 部署及运行

    在JDK8环境下,部署到Tomcat8.0.x/Tomcat8.5.x/Wildfly10.x/Glassfish4.x,正常运行。如下图所示:

     

    WebSocket原理及技术

    31 WebSocket Echo Example

    4.  结论

    WebSocket和传统的HTTP交互方式的区别如下图:

    WebSocket原理及技术

    41交互方式比较

     

    WebSocket的结论如下:

    • 基于TCP/IP协议实现

    • 是一种全双向的通信, 具有底层socket的特点

    • 节约带宽,节省服务器资源

    • 是HTML5的技术之一,具有巨大的应用前景

     

    本文的完整示例代码: https://github.com/siwind/HelloWebJava

     

     

    参考文献

     

    [1] Dan Kegel. The C10K problem[EB/OL]. http://www.kegel.com/c10k.html.

    [2] Head-of-line blocking[EB/OL]. https://en.wikipedia.org/wiki/Head-of-line_blocking.

    [3] W3C Candidate Recommendation 20 September 2012. The WebSocket API[EB/OL]. https://www.w3.org/TR/websockets/.

     

  • 相关标签: websocket