目录

  前言

  后端

  浏览器前端

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:\workspace\WebSocket\WebRoot\WEB-INF\lib,而部署的应用lib目录是在D:\tools\apache-tomcat-7.0.32\webapps\WebSocket\WEB-INF\lib,删掉部署目录的lib目录中连两个jar就可以了,否则会包Could not initialize class com.ibcio.WebSocketMessageServlet错误。

 2.Tomcat8安装包里有WebSocket的demo

3.html5 才支持WebSocket 

html5_websocket_tomcat8的更多相关文章

随机推荐

  1. String和StringBuffer的机制差别

    String是不可变的,StringBuffer是可变的:StringBuffer是线程安全的,StringBuilder是非线程安全的. 因而在大部分情况下字符串的拼接速度为:StringBuild ...

  2. [BZOJ1069][SCOI2007]最大土地面积(水平扫描法求凸包+旋转卡壳)

    题意:在某块平面土地上有N个点,你可以选择其中的任意四个点,将这片土地围起来,当然,你希望这四个点围成. 的多边形面积最大.n<=2000. 先求凸包,再枚举对角线,随着对角线的斜率上升,另外两 ...

  3. POJ 1180 Batch Scheduling(斜率优化DP)

    [题目链接] http://poj.org/problem?id=1180 [题目大意] N个任务排成一个序列在一台机器上等待完成(顺序不得改变), 这N个任务被分成若干批,每批包含相邻的若干任务. ...

  4. 【递归】【栈】先修课 计算概论(A)/函数递归练习(2)5:布尔表达式

    总时间限制: 1000ms 内存限制: 65536kB 描述 输入一个布尔表达式,请你输出它的真假值. 比如:( V | V ) & F & ( F | V ) V表示true,F表示 ...

  5. 【主席树】bzoj2588 Spoj 10628. Count on a tree

    每个点的主席树的root是从其父转移来的.询问的时候用U+V-LCA-FA(LCA)即可. #include<cstdio> #include<algorithm> using ...

  6. Exercise01_03

    public class TuAn{ public static void main(String[] args){ System.out.println(" J A V V A" ...

  7. catalina_home与catalina_base

    CATALINA_HOME是Tomcat的安装目 录,CATALINA_BASE是Tomcat的工作目录. 如果我们想要运行Tomcat的多个实例,但是不想安装多个Tomcat软件副本.那么我们可以配 ...

  8. Mysql 按条件排序查询一条记录 top 1 对应Mysql的LIMIT 关键字

    项目中需要每次查询一个表中的最新的一条记录,表结构里面有日期字段.只需要显示一条记录. Mysql帮助文档里面的解释 3.6.2. 拥有某个列的最大值的行 任务:找出最贵物品的编号.销售商和价格. 这 ...

  9. 关于java的关键字 transient

    我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,Java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的过程,只要这个类实现了Serilizable ...

  10. jquery获取下拉列表的值和显示内容的方法

    页面的下拉列表: 选择时间段: <select name="timespan" id="timespan" class="Wdate" ...