反向Ajax之WebSocket

WebSocket是HTML5开始提供的一种浏览器与服务器间进行全双工通讯的网络技术。

反向Ajax在观察者模型、聊天系统中应用的越来越多。如股票,监控等系统。

以聊天系统为例,如果没有服务器推的技术,Web聊天系统只能以固定的时间间隔轮询服务器。
这会产生大量的无用的连接,对服务器造成巨大压力。
在单位写过一个IM聊天系统,在配置了线程池,内存缓存等优化手段之后,通过loadrunner压力测试,并发访问量却始终超不过200/s。在这种系统中,轮询是一种噩梦。

WebSocket作为服务器推(反向Ajax)的手段之一,可以解决这种需求。
下面的例子,简单介绍了WebSocket的使用。
服务器每隔3秒,将自身的内存信息推送到所有连接的客户端浏览器。如果客户端浏览器点击按钮,则立即对该客户端返回最新的信息。
页面:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>WebSocket</title>
<script type="text/javascript"
    src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
<script type="text/javascript">
    var ws = null;
    function startWebSocket() {
        if ('WebSocket' in window) {
            ws = new WebSocket('ws://127.0.0.1:8080/Web/ws.do');
        } else if ('MozWebSocket' in window) {
            ws = new MozWebSocket('ws://127.0.0.1:8080/Web/ws.do');
        } else {
            alert('浏览器不支持WebSocket');
        }

        ws.onmessage = function(evt) {
            $('#content').html(evt.data);
        }

        ws.onclose = function(evt) {
            $('#content').html('WebSocket关闭');
        }

        ws.onopen = function(evt) {
            $('#content').html('WebSocket已经打开');
        }
    }

    function getJVMInfo() {
        //随便发点什么
        ws.send(new Date());
    }

    $(document).ready(function() {
        startWebSocket();
    });
</script>
</head>
<body>
    <input type="button" value="立即获取" onclick="getJVMInfo();" />
    <div id="content"></div>
</body>
</html>
代码:

import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

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

/**
 * Servlet implementation class InitServlet
 */
@WebServlet("/ws.do")
public class InitServlet extends WebSocketServlet implements Runnable {
    List<JVMMessageInbound> list = new CopyOnWriteArrayList<JVMMessageInbound>();
    ScheduledExecutorService singleThread = Executors.newSingleThreadScheduledExecutor();
    {
        singleThread.scheduleWithFixedDelay(this, 3, 3, TimeUnit.SECONDS);
    }

    @Override
    protected StreamInbound createWebSocketInbound(String arg0, HttpServletRequest arg1) {
        return new JVMMessageInbound();
    }

    private class JVMMessageInbound extends MessageInbound {

        @Override
        protected void onBinaryMessage(ByteBuffer arg0) throws IOException {
        }

        @Override
        protected void onTextMessage(CharBuffer arg0) throws IOException {
            CharBuffer cb = CharBuffer.wrap(arg0);
            String data = cb.toString();
            System.out.println(data);
            this.getWsOutbound().writeTextMessage(CharBuffer.wrap(getJVMInfo()));
            this.getWsOutbound().flush();
        }

        @Override
        protected void onClose(int status) {
            System.out.println("Close WebSocket");
            super.onClose(status);
            list.remove(this);
        }

        @Override
        protected void onOpen(WsOutbound outbound) {
            System.out.println("Open new WebSocket");
            super.onOpen(outbound);
            list.add(this);
        }

    }

    private String getJVMInfo() {
        long useMemory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
        useMemory = useMemory / 1024;
        return "已用内存:" + String.valueOf(useMemory) + "K";
    }

    @Override
    public void run() {
        System.out.println("发送广播通知");
        String data = "广播通知\n" + new Date() + "\n" + getJVMInfo();
        for (JVMMessageInbound m : list) {
            try {
                m.getWsOutbound().writeTextMessage(CharBuffer.wrap(data));
                m.getWsOutbound().flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}
效果截图:

但是在Tomcat 7.0.47版本中,WebSocketServlet已经标识为deprecated,并可能在Tomcat 8中remove。
是不是设计了更好的API



来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/29254281/viewspace-1064838/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/29254281/viewspace-1064838/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值