websocket与Java实例

WebSocket是HTML5新增的协议,实现web实时通信。本文介绍了WebSocket的原理、支持情况及一个简单的Java前后端通信示例,包括握手过程、关键参数和事件、以及服务端和客户端的实现方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

websocket是H5里新增的一种技术,主要用于web客户端与服务端之间建立双工通信通道,进行实时消息传输。在websocket之前,web客户端与服务器之间传递消息都是基于HTTP协议,总所周知,HTTP是一种无状态的协议,web客户端与服务端传递消息必须由客户端主动request,然后服务端返回response结果,服务端无法主动推送消息给客户端。为此,出现了轮询(polling)和Comet技术,这里不做详细介绍,有兴趣可以自己研究一下。轮询(polling)和Comet的本质还是基于HTTP的请求,虽在性能上有不少提升,但在并发量环境下,对服务器要求较高。HTML5推出的WebSocket,才真正实现了Web的实时通信,使B/S模式具备了C/S模式的实时通信能力。好了,言归正传,结合实例讲一下websocket如何使用。
1、websocket原理
webscoket也是一种基于TCP的协议,与HTTP类似。websocket实现双工通信分为两步:
(1)握手:客户端与服务器进行握手,客户端通过http协议向服务器发出握手请求,服务器响应客户端的握手请求。
客户端到服务端:

GET /demo HTTP/1.1 
Host: example.com 
Connection: Upgrade 
Sec-WebSocket-Key2: 12998 5 Y3 1 .P00 
Upgrade: WebSocket 
Sec-WebSocket-Key1: 4@1 46546xW%0l 1 5 
Origin: http://example.com 
[8-byte security key] 

服务端到客户端:

HTTP/1.1 101 WebSocket Protocol Handshake 
Upgrade: WebSocket 
Connection: Upgrade 
WebSocket-Origin: http://example.com 
WebSocket-Location: ws://example.com/demo 
[16-byte hash response]

客户端通过Upgrade命令请求服务器,把协议升级为websocket协议,并传递一个秘钥Sec-WebSocket-Key1给服务端,服务端响应请求。
(2)通信:握手完成后,客户端与服务端之间的双工通道建立成功,双方可以进行实时通信。
相比传统基于HTTP协议的通信,websocket只在发送握手请求的时候进行了一次HTTP请求,资源占用大大减少。

2、websocket支持
(1)前端websocket支持:在H5中嵌入websocket对象,实现了对websocket支持
websocket js定义:

[Constructor(in DOMString url, in optional DOMString protocol)] 
 interface WebSocket { 
   readonly attribute DOMString URL; 
        // ready state 
   const unsigned short CONNECTING = 0; 
   const unsigned short OPEN = 1; 
   const unsigned short CLOSED = 2; 
   readonly attribute unsigned short readyState; 
   readonly attribute unsigned long bufferedAmount; 
   //networking 
   attribute Function onopen; 
   attribute Function onmessage; 
   attribute Function onclose; 
   attribute Function onerror;
   boolean send(in DOMString data); 
   void close(); 
 }; 
 WebSocket implements EventTarget;

介绍一下对象中几个关键的参数和事件:
URL:客户端连接的服务端地址;
onopen:客户端与服务端通过websocket连接成功时回调;
onmessage:客户端收到服务端消息时回调;
onclose:客户端与服务端之间的websocket通道断开时回调;
onerror:websocket连接出错时回调;
send:websocket对象通过此方法向服务器发消息;
close:websocket对象通过此方法主动关闭连接。

(2)服务端websocket支持:根据websocket版本不同,服务端对websocket支持分为两种:
a 在JavaEE7以前的版本,服务端对websocket的支持都是采用服务器中集成的相关类,
比如tomcat在7.0.27版本开始对websocket支持(websocket1.0),7.0.47版本对websocket1.1支持。使用tomcat提供websocket服务端支持,需引入catalina.jar和tomcat-coyote.jar。注意:这两个jar包千万不要放在WEB-INF/lib目录下,会和tomcat中的jar包发生冲突;
b 从JavaEE7版本开始,Java中集成了websocket,提供了对websocket支持,此时的websocket
即是websocket1.1,和tomcat7.0.47版本中的websocket一致。

3、websocket通信demo
(1)web客户端:

function connect() {  
        var target = 'ws://' + window.location.host   
            + "/websocketTest/HelloWebSocketServlet";  
         if ('WebSocket' in window) {  
                ws = new WebSocket(target);  
            } else if ('MozWebSocket' in window) {  
                ws = new MozWebSocket(target);  
            } else {  
                alert('WebSocket is not supported by this browser.');  
                return;  
            }  

            ws.onopen = function (event) {  
                $("#outputPanel").text("WebSocket has opened, Waiting message.......");
            };  

            ws.onmessage = function (event) {  
                $("#outputPanel").text(event.data);  
            };  

            ws.error = function (event){
                $("#outputPanel").text("WebSocket error:" + event);
            }
            ws.onclose = function () {  
                $("#outputPanel").text("WebSocket has closed");  
            };  
        }  
function sendMessage(message){
        ws.send(message); 
    }
function disconnect() {  
        if (ws != null) {  
        ws.close(); 
        ws = null; 
        }  
    }       

客户端js代码中new一个websocket对象的时候,向服务端发起连接请求,注意URL前缀的协议是ws或wss(加密),而不是http。无论是websocket1.0还是websocket1.1版本,前端的实现都是一样的!

(2)服务端:服务端主要实现对两个类继承,WebSocketServlet(httpServlet的子类)和StreamInbound。前者监听客户端的websocket连接请求,并执行createWebSocketInbound()方法返回一个StreamInbound对象;
后者与客户端进行通信,一般都是采用其子类MessageInbound;
监听websocket连接请求:

package com.websocket.servlet;

import java.util.concurrent.atomic.AtomicInteger;

import javax.servlet.http.HttpServletRequest;

import org.apache.catalina.websocket.StreamInbound;
import org.apache.catalina.websocket.WebSocketServlet;

public class HelloWebSocketServlet extends WebSocketServlet {  
    private static final long serialVersionUID = 1L;  

    private final AtomicInteger connectionIds = new AtomicInteger(0);  
    @Override  
    protected StreamInbound createWebSocketInbound(String arg0,  
            HttpServletRequest request) {  
        return new HelloMessageInbound(connectionIds.getAndIncrement(), request  
                .getSession().getId());  
    }  
}  

与客户端进行通信:
package com.websocket.servlet;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.sql.Time;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.catalina.websocket.MessageInbound;
import org.apache.catalina.websocket.WsOutbound;



public class HelloMessageInbound extends MessageInbound {  

    private String WS_NAME;  
    private final String FORMAT = "%s : %s";  
    private final String PREFIX = "ws_";  
    private String sessionId = "";  
    private String filename = "";

    public HelloMessageInbound(int id, String _sessionId) {  
        this.WS_NAME = PREFIX + id;  
        this.sessionId = _sessionId;  
    }  

    @Override  
    protected void onClose(int status) {  
        System.out.println(String.format(FORMAT, WS_NAME, "closing ......"));  
        super.onClose(status);  
    }  

    @Override  
    protected void onOpen(WsOutbound outbound) {  
        super.onOpen(outbound);  
        try {
            send(this.sessionId + "连接成功!");
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
    }  

    private void send(String message) throws IOException {  
        message = String.format(FORMAT, WS_NAME, message); 
        System.out.println(message);  
        getWsOutbound().writeTextMessage(CharBuffer.wrap(message));  
    }  

    @Override
    protected void onBinaryMessage(ByteBuffer arg0) throws IOException {
        // TODO Auto-generated method stub
        System.out.println("this is BinaryMessage:"+arg0.toString());
    }

    @Override
    protected void onPong(ByteBuffer payload) {
        // TODO Auto-generated method stub
        super.onPong(payload);
        System.out.println("this is Pong:"+payload.toString());
    }
    @Override
    protected void onTextMessage(CharBuffer arg0) throws IOException {
        // TODO Auto-generated method stub
        filename = arg0.toString();
        System.out.println("hello");
        System.out.println("this is TextMessage:"+arg0.toString());
//      new Thread(new Runnable() { 
//          
//          @Override
//          public void run() {
//              // TODO Auto-generated method stub
//              Integer cacheTime = 1000;
//              Timer timer = new Timer();
//              timer.schedule(new TimerTask() {
//                  
//                  @Override
//                  public void run() {
//                      // TODO Auto-generated method stub
//                       Date date = new Date();
//                       SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd,HH:mm:ss");
//                      try {
//                          send(sd.format(date));
//                      } catch (IOException e) {
//                          // TODO Auto-generated catch block
//                          e.printStackTrace();
//                      }
//                  }
//              }, 5000, cacheTime);
//          }
//      }).start();
    }

}  

其中,onOpen()在websocket连接成功时执行,onClose()在websocket连接断开时执行,onTextMessage()用于接收客户端发送的文本消息,onBinaryMessage()用于接收客户端发送的二进制消息,websocket1.0版本
向客户端发送消息getWsOutbound().writeTextMessage(CharBuffer.wrap(message));,websocket1.1向客户端发送消息,从session中获取session.getAsyncRemote().sendText(arg0);
好了,这就是我对websocket的研究结果,比较浅显,有需要的还可以查看Java Websocket API,里面很详细描述了各个类的继承关系和方法的使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值