zoukankan      html  css  js  c++  java
  • html5_websocket_tomcat8

    目录

      前言

      后端

      浏览器前端

          java的client

      注意

    前言

    HTML5 WebSocket实现了服务器与浏览器的双向通讯,开销小,实时性高,常用于即时通讯和对信息实时性要求比较高的应用。
    下面讲解如利用Tomcat8+WebSocket开发聊天室。
    目前Spring已经推出了WebSocket的API,能够兼容各个服务器的实现

    后端

     说明 

    @ServerEndpoint("/echo") 的 annotation 注释端点表示将 WebSocket 服务端运行在 ws://[Server 端 IP 或域名]:[Server 端口]/websockets/echo 的访问端点,客户端浏览器已经可以对 WebSocket 客户端 API 发起 HTTP 长连接了。使用 ServerEndpoint 注释的类必须有一个公共的无参数构造函数,
    @onMessage 注解的 Java 方法用于接收传入的 WebSocket 信息,这个信息可以是文本格式,可以是json数据,也可以是二进制格式。
    @OnOpen 在这个端点一个新的连接建立时被调用。参数提供了连接的另一端的更多细节。Session 表明两个 WebSocket 端点对话连接的另一端,可以理解为类似 HTTPSession 的概念。
    @OnClose 在连接被终止时调用。参数 closeReason 可封装更多细节,如为什么一个 WebSocket 连接关闭。
    @Message 注释,MaxMessageSize 属性可以被用来定义消息字节最大限制,在示例程序中,如果超过 6 个字节的信息被接收,就报告错误和连接关闭。

       ChatServer.java

    import java.io.IOException;
    import java.util.concurrent.CopyOnWriteArraySet;
    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;

    //该注解用来指定一个URI,客户端可以通过这个URI来连接到WebSocket。类似Servlet的注解mapping。无需在web.xml中配置。
    @ServerEndpoint("/ws/chat/{nickName}")
    public class ChatServer {
      //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
      private static int onlineCount = 0;
      //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识
      private static CopyOnWriteArraySet<ChatServer> webSocketSet = new CopyOnWriteArraySet<ChatServer>();
      //与某个客户端的连接会话,需要通过它来给客户端发送数据
      private Session session;
      private String nickName;
      /**
      * 连接建立成功调用的方法
      * @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
      */
      @OnOpen
      public void onOpen(Session session, @PathParam(value = "nickName") String nickName){
        this.session = session;
        this.nickName = nickName;
        webSocketSet.add(this); //加入set中
        String message = String.format("System> %s %s", this.nickName, " 加入.");
        broadCast(message);
        addOnlineCount(); //在线数加1
        System.out.println(nickName+"新加入!当前在线人数为" + getOnlineCount());
      }

      /**
      * 连接关闭调用的方法
      */
      @OnClose
      public void onClose(){
        webSocketSet.remove(this);   //从set中删除
        subOnlineCount();         //在线数减1
        String message = String.format("System> %s, %s", this.nickName, " 离开.");
        broadCast(message);
        System.out.println(this.nickName+"离开!当前在线人数为" + getOnlineCount());
      }


      /**
      * 收到客户端消息后调用的方法
      * @param message 客户端发送过来的消息
      * @param session 可选的参数
      */
      @OnMessage
      public void onMessage(String message, Session session, @PathParam(value = "nickName") String nickName) {
        System.out.println(nickName+":" + message);
        broadCast(nickName + ">" + message);
      }

      /**
      * 发生错误时调用
      * @param session
      * @param error
      */
      @OnError
      public void onError(Session session, Throwable throwable) {
        System.out.println("发生错误");
        System.out.println(throwable.getMessage());
      }


      /**
      * 发送或广播信息
      * @param message
      */
      private void broadCast(String message) {
        //群发消息
        for (ChatServer chat : webSocketSet) {
        try {
          synchronized (chat) {
            chat.session.getBasicRemote().sendText(message);
          }
        } catch (IOException e) {
          webSocketSet.remove(chat);
          try {
              chat.session.close();
            } catch (IOException e1) {
          }
            broadCast(String.format(" %s %s", chat.nickName, " has bean disconnection."));
          }
        }
      }

      public static synchronized int getOnlineCount() {
        return onlineCount;
      }

      public static synchronized void addOnlineCount() {
        ChatServer.onlineCount++;
      }

      public static synchronized void subOnlineCount() {
        ChatServer.onlineCount--;
      }
    }

    前端

      chat.jsp 

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    <%
       String path = request.getContextPath();
       String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
       String nickName=request.getParameter("nickName");
    %>
    <!DOCTYPE HTML>
    <html>
    <head>
       <base href="<%=basePath%>">
       <title>My WebSocket</title>
    </head>
    <body>
       Welcome   <br />
       <div id="message"></div> 
       <input id="text" type="text" />
       <button onclick="send()">Send</button>
       <button onclick="closeWebSocket()">Close</button>
    </body> 
    <script type="text/javascript">
       var websocket = null;
       //判断当前浏览器是否支持WebSocket
       if ('WebSocket'in window) {
          websocket = new WebSocket("ws://localhost:8080/webSocket/ws/chat/<%=nickName%>");
       } else {
          alert('Not support websocket')
       }
       //连接发生错误的回调方法
       websocket.onerror = function() {
          setMessageInnerHTML("error");
       };
       //连接成功建立的回调方法
       websocket.onopen = function(event) {
          setMessageInnerHTML("open");
       }
       //接收到消息的回调方法
       websocket.onmessage = function() {
          setMessageInnerHTML(event.data);
       }
       //连接关闭的回调方法
       websocket.onclose = function() {
          setMessageInnerHTML("close");
       }
       //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
       window.onbeforeunload = function() {
          websocket.close();
       }
       //将消息显示在网页上
       function setMessageInnerHTML(innerHTML) {
          document.getElementById('message').innerHTML += innerHTML + '<br/>';
       } 
       //关闭连接
       function closeWebSocket() {
          websocket.close();
       } 
       //发送消息
       function send() {
          var message = document.getElementById('text').value;
          websocket.send(message);
       }
    </script> 
    </html>

    访问

    http://127.0.0.1:8080/webSocket/chat.jsp?nickName=dengzy

    http://127.0.0.1:8080/webSocket/chat.jsp?nickName=dengbw 

    java的client

      java_websocket.

    import java.net.URI;

    import java.net.URISyntaxException;

    import java.util.Scanner; 

    import org.java_websocket.client.WebSocketClient;

    import org.java_websocket.drafts.Draft_17;

    import org.java_websocket.handshake.ServerHandshake; 

    publicclass TestTocatWebSocket {

     

       publicstaticvoid main(String[] args) throws URISyntaxException { 

          String url = "ws://localhost:8080/webSocket/ws/chat/"+ args[0] ;//

          WebSocketClient wc = new WebSocketClient(new URI(url), new Draft_17()) { 

             @Override

             publicvoid onOpen(ServerHandshake handshakedata) {

                System.out.println(handshakedata.getHttpStatusMessage());

             } 

             @Override

             publicvoid onMessage(String message) {

                System.out.println(message);

             } 

             @Override

             publicvoid onError(Exception ex) {

             } 

             @Override

             publicvoid onClose(intcode, String reason, booleanremote) {

             }

          }; 

          wc.connect(); 

          while (true) {

             Scanner scanner = new Scanner(System.in);

             String message = scanner.nextLine();

             if (message.equals("q")) {

                wc.close();

                break;

             }

             scanner.close();

             wc.send(message);

          }

       }

    } 

    注意

     1.在部署完成之后需要将在tomcat应用目录中的lib目录下的catalina.jar和tomcat-coyote.jar删掉,比如项目的lib目录在D:workspaceWebSocketWebRootWEB-INFlib,而部署的应用lib目录是在D: oolsapache-tomcat-7.0.32webappsWebSocketWEB-INFlib,删掉部署目录的lib目录中连两个jar就可以了,否则会包Could not initialize class com.ibcio.WebSocketMessageServlet错误。

     2.Tomcat8安装包里有WebSocket的demo

       3.html5 才支持WebSocket 

  • 相关阅读:
    定时清理日志的shell脚本
    图解 Elestricsearch 写入流程
    消息队列产生严重消息堆积怎么处理?
    消息队列如何确保消息的有序性?
    架构模式 CQRS
    消息队列把消息弄丢了怎么办?
    3 个主流 Java 微服务框架
    RabbitMQ、Kafka、RocketMQ 是如何实现高可用的?
    Kafka 不再需要 ZooKeeper
    微服务设计原则
  • 原文地址:https://www.cnblogs.com/dengzy/p/5424184.html
Copyright © 2011-2022 走看看