websocket聊天室

来源:互联网 发布:女性健康知讲座 编辑:程序博客网 时间:2024/05/16 01:59

环境:eclipse即可

WebSocket技术的优点有:

1)通过第一次HTTP Request建立了连接之后,后续的数据交换都不用再重新发送HTTP Request,节省了带宽资源;

2) WebSocket的连接是双向通信的连接,在同一个TCP连接上,既可以发送,也可以接收; 3)具有多路复用的功能(multiplexing),

也即几个不同的URI可以复用同一个WebSocket连接。这些特点非常类似TCP连接,但是因为它借用了HTTP协议的一些概念,

所以被称为了WebSocket。

实现websocket接口,定义了双向通信的公共接口。

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

  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: 当相应的事件发生时会触发此回调函数
服务器代码:
import java.io.IOException;import java.util.concurrent.CopyOnWriteArraySet;import java.util.concurrent.atomic.AtomicInteger;import javax.websocket.OnClose;import javax.websocket.OnMessage;import javax.websocket.OnOpen;import javax.websocket.Session;import javax.websocket.server.ServerEndpoint;//该注解用来指定一个URI,客户端可以通过这个URI来连接到WebSocket。类似Servlet的注解mapping。无需在web.xml中配置。@ServerEndpoint("/webSocket")public class webSocket {    // 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。    private  static final AtomicInteger onlineCount = new AtomicInteger(0);    // concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识    private static CopyOnWriteArraySet<webSocket> webSocketSet = new CopyOnWriteArraySet<webSocket>();    //定义一个记录客户端的聊天昵称    private final String nickname;    // 与某个客户端的连接会话,需要通过它来给客户端发送数据    private Session session;    public  webSocket() {        nickname = "访客"+onlineCount.getAndIncrement();     }    /*     *使用@Onopen注解的表示当客户端链接成功后的回掉。参数Session是可选参数     这个Session是WebSocket规范中的会话,表示一次会话。并非HttpSession     */    @OnOpen    public void onOpen(Session session) {        this.session = session;        webSocketSet.add(this);        String message = String.format("[%s,%s]",nickname,"加入聊天室");        broadcast(message);        System.out.println("onOpen");    }/*     *使用@OnMessage注解的表示当客户端发送消息后的回掉,第一个参数表示用户发送的数据。参数Session是可选参数,与OnOpen方法中的session是一致的     */    @OnMessage    public void onMessage(String message,Session session){    //这里当然会打印true        System.out.println(this.session==session);        broadcast(String.format("%s:%s",nickname,filter(message)));    }/**用户断开链接后的回调,注意这个方法必须是客户端调用了断开链接方法后才会回调*/    @OnClose    public void onClose() {        webSocketSet.remove(this);        String message = String.format("[%s,%s]",nickname,"离开了聊天室链接");        broadcast(message);    }    //完成群发    private void broadcast(String info){        for(webSocket w:webSocketSet){            try {                synchronized (webSocket.class) {                    w.session.getBasicRemote().sendText(info);                }            } catch (IOException e) {                System.out.println("向客户端"+w.nickname+"发送消息失败");                webSocketSet.remove(w);                try {                    w.session.close();                } catch (IOException e1) {}                String message = String.format("[%s,%s]",w.nickname,"已经断开链接");                broadcast(message);            }        }    }    //对用户的消息可以做一些过滤请求,如屏蔽关键字等等。。。    public static String filter(String message){        if(message==null){            return null;        }        return message;    }}

html客户端:

<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Insert title here</title><script type="text/javascript">    var ws = new WebSocket("ws://localhost:8080/Websocket_NetChat/webSocket");    /*     *监听三种状态的变化 。js会回调     */    ws.onopen = function(message) {    };    ws.onclose = function(message) {    };    ws.onmessage = function(message) {        showMessage(message.data);    };    //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。window.onbeforeunload = function() {        ws.close();    };    //关闭连接    function closeWebSocket() {        ws.close();    }    //发送消息    function send() {        var input = document.getElementById("msg");        var text = input.value;        ws.send(text);        input.value = "";    }    function showMessage(message) {        var text = document.createTextNode(message);        var br = document.createElement("br")        var div = document.getElementById("showChatMessage");        div.appendChild(text);        div.appendChild(br);    }</script></head><body>    <div        style="width: 600px; height: 240px; overflow-y: auto; border: 1px solid #333;"        id="show">        <div id="showChatMessage"></div>        <input type="text" size="80" id="msg" name="msg" placeholder="输入聊天内容" />        <input type="button" value="发送" id="sendBn" name="sendBn"            onclick="send()"></body></html>
用法总结:

1. private  static final AtomicInteger onlineCount = new AtomicInteger(0);这里的记录当前在线连接数可以替换为登录账号名或者id都行

2. private static CopyOnWriteArraySet<webSocket> webSocketSet = new CopyOnWriteArraySet<webSocket>();用来保存当前在线的websock
3. broadcast(message);将消息发给webSocketSet 中所有在线的客户端

4.synchronized (webSocket.class) {
                    w.session.getBasicRemote().sendText(info); //同步的方式将消息发给其他webSocket,实现消息群发,若没有这句消息将不会发送
                }

5.filter(String message)//充当过滤器