程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> JSP編程 >> 關於JSP >> 基於jsp+tomcat7.047+html5的websocket簡單demo

基於jsp+tomcat7.047+html5的websocket簡單demo

編輯:關於JSP

 

WebSocket

WebSocket 規范的目標是在浏覽器中實現和服務器端雙向通信。雙向通信可以拓展浏覽器上的應用類型,例如實時的數據推送(股票行情)、游戲、聊天等。

原理

WebSocket protocol 是HTML5一種新的協議(protocol)。它是實現了浏覽器與服務器全雙工通信(full-duplex)。 現很多網站為了實現即時通訊(real-time),所用的技術都是輪詢(polling)。輪詢是在特定的的時間間隔(time interval)(如每1秒),由浏覽器對服務器發出HTTP request,然後由服務器返回最新的數據給客服端的浏覽器。這種傳統的HTTP request d的模式帶來很明顯的缺點 – 浏覽器需要不斷的向服務器發出請求(request),然而HTTP request 的header是非常長的,裡面包含的數據可能只是一個很小的值,這樣會占用很多的帶寬。 而最比較新的技術去做輪詢的效果是Comet – 用了AJAX。但這種技術雖然可達到全雙工通信,但依然需要發出請求(reuqest)。 在 WebSocket API,浏覽器和服務器只需要要做一個握手的動作,然後,浏覽器和服務器之間就形成了一條快速通道。兩者之間就直接可以數據互相傳送。在此WebSocket 協議中,為我們實現即時服務帶來了兩大好處: 1. Header 互相溝通的Header是很小的-大概只有 2 Bytes 2. Server Push 服務器可以主動傳送數據給客戶端

3握手協議

在實現websocket連線過程中,需要通過浏覽器發出websocket連線請求,然後服務器發出回應,這個過程通常稱為“握手” (handshaking)。 PS1:握手協議在後期的版本中,會標明版本編號,下面的例子屬於早期的協定之一,對於新版的 chrome 和 Firefox 皆不適用。 PS2:後期的版本大多屬於功能上的擴充,例如使用第7版的握手協議同樣也適用於第8版的握手協議。 例子: 浏覽器請求 GET /demo HTTP/1.1 Host: 你的網址.com Connection: Upgrade Sec-WebSocket-Key2: 12998 5 Y3 1 .P00 Upgrade: WebSocket Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5 Origin: http://你的網址.com ^n:ds[4U 服務器回應 HTTP/1.1 101 WebSocket Protocol Handshake Upgrade: WebSocket Connection: Upgrade Sec-WebSocket-Origin: http://你的網址.com Sec-WebSocket-Location: ws://你的網址.com/demo Sec-WebSocket-Protocol: sample 8jKS’y:G*Co,Wxa-

4浏覽器

實現了websocket的浏覽器: Chrome Supported in version 4+ Firefox Supported in version 4+ Internet Explorer Supported in version 10+ Opera Supported in version 10+ Safari Supported in version 5+

5服務器

在服務器端,也出現了一些實現websocket協議的項目: jetty 7.0.1 包含了一個初步的實現 resin 包含有websocket 實現 pywebsocket, apache http server 擴展 apache tomcat 7.0.27 版本 Nginx 1.3.13 版本 websocket api在浏覽器端的廣泛實現似乎只是一個時間問題了, 值得注意的是服務器端沒有標准的api, 各個實現都有自己的一套api, 並且jcp也沒有類似的提案, 所以使用websocket開發服務器端有一定的風險.可能會被鎖定在某個平台上或者將來被迫升級. 得意咳咳,以上這大坨來自百度百科,欲知詳細請自行查找
吐舌頭好了,准備開發環境:java sdk7,Myeclipse10,Tomcat7.47大笑下載好了自行安裝,我不管了
打開MyEclipse新建一個JSP工程,然後導入catalina.jar,websocket-api.jar可憐什麼,你覺得不爽,那你就多導幾個吧,反正不要錢,也沒人強奸你!
\
\
Ok,接下來,新建一個類WebsocketConfig ,有關抽象類ServerApplicationConfig請查看javaEE7 api敲打這個很重要,你知道嗎,我不哆嗦,你往下看
package com.websocket;

import java.util.HashSet;
import java.util.Set;

import javax.websocket.Endpoint;
import javax.websocket.server.ServerApplicationConfig;
import javax.websocket.server.ServerEndpointConfig;

public class WebsocketConfig implements ServerApplicationConfig{

	@Override
	public Set> getAnnotatedEndpointClasses(Set> scanned) {
		// TODO Auto-generated method stub
		System.out.println(******getAnnotatedEndpointClasses******);
		// Deploy all WebSocket endpoints defined by annotations in the examples
        // web application. Filter out all others to avoid issues when running
        // tests on Gump
		//這主要是掃描類的包,如果前綴為com.websocket.就抓住她,然後做什麼,你懂的
		Set> res=new HashSet<>();
		for(Class cs:scanned){
			if(cs.getPackage().getName().startsWith(com.websocket.)){
				res.add(cs);
			}
		}
		return res;
	}

	@Override
	public Set getEndpointConfigs(
			Set> scanned) {
		// TODO Auto-generated method stub
		System.out.println(******getEndpointConfigs******);
		Set res=new HashSet<>();
		/*
	   //使用Programmatic api的服務器地址

		if (scanned.contains(EchoEndpoint.class)) {
            res.add(ServerEndpointConfig.Builder.create(
                    EchoEndpoint.class,
                    /websocket/echoProgrammatic).build());
        }
        */
		return res;
	}

}

好了,現在我們來建立一個簡單chat的ServerEndpoint,據說有兩種方式:1、使用@ServerEndpoint 2、采用繼承的方式 我們先來第一種,新建一個類chat1
package com.websocket.chat;

import java.io.IOException;
import java.util.Set;
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;
import util.HTMLFilter;

@ServerEndpoint(value=/chat01)
//用了這個之後,你的服務地址為ws://localhost:port/projectName/chat01

public class chat_1 {
    private static final AtomicInteger connectionIds = new AtomicInteger(0);
    private static final Set connections =
            new CopyOnWriteArraySet();

    private final String nickname;
    private Session session;

    public chat_1() {
        nickname = 游客ID: + connectionIds.getAndIncrement();
    }


    @OnOpen
    public void start(Session session) {
        this.session = session;
        connections.add(this);
        String message = String.format(嗨嗨,姑娘們,來接客了: %s %s, nickname, has joined.);
        broadcast(message);
    }


    @OnClose
    public void end() {
        connections.remove(this);
        String message = String.format(客官慢走,嘿嘿,還沒付錢呢: %s %s,
                nickname, has disconnected.);
        broadcast(message);
    }


    @OnMessage
    public void receive(String message) {
        // Never trust the client
        String filteredMessage = String.format(您有新消息:%s: %s,
                nickname, HTMLFilter.filter(message.toString()));
        broadcast(filteredMessage);
    }


    private static void broadcast(String msg) {
        for (chat_1 client : connections) {
            try {
                client.session.getBasicRemote().sendText(msg);
            } catch (IOException e) {
                connections.remove(client);
                try {
                    client.session.close();
                } catch (IOException e1) {
                    // Ignore
                }
                String message = String.format(* %s %s,
                        client.nickname, has been disconnected.);
                broadcast(message);
            }//try 
        }//for
    }//void broadcast(String msg)
}
/*
 * 你可能已經注意到我們從 javax.websocket包中引入了一些類。
@ServerEndpoint 注解是一個類層次的注解,它的功能主要是將目
前的類定義成一個websocket服務器端。注解的值將被用於監聽用戶連
接的終端訪問URL地址。
onOpen 和 onClose 方法分別被@OnOpen和@OnClose 所注解。
這兩個注解的作用不言自明:他們定義了當一個新用戶連接和斷開的時候所調
用的方法。
onMessage 方法被@OnMessage所注解。這個注解定義了當服務器接
收到客戶端發送的消息時所調用的方法。注意:這個方法可能包含一個
javax.websocket.Session可選參數(在我們的例子裡就是
session參數)。如果有這個參數,容器將會把當前發送消息客戶端的連接
Session注入進去。
 */


index.jsp
<%@ page language=java import=java.util.* pageEncoding=ISO-8859-1%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+://+request.getServerName()+:+request.getServerPort()+path+/;
%>


>
  • chat01


  • chat02

\

\
OK,接下來,我們用第二種方法,這也是本人比較喜歡的方法

 

 

/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the License); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an AS IS BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package websocket.echo;

import java.io.IOException;

import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import javax.websocket.MessageHandler;
import javax.websocket.RemoteEndpoint;
import javax.websocket.Session;

public class EchoEndpoint extends Endpoint {

    @Override
    public void onOpen(Session session, EndpointConfig endpointConfig) {
        RemoteEndpoint.Basic remoteEndpointBasic = session.getBasicRemote();
        session.addMessageHandler(new EchoMessageHandler(remoteEndpointBasic));
    }

    private static class EchoMessageHandler
            implements MessageHandler.Whole {

        private final RemoteEndpoint.Basic remoteEndpointBasic;

        private EchoMessageHandler(RemoteEndpoint.Basic remoteEndpointBasic) {
            this.remoteEndpointBasic = remoteEndpointBasic;
        }

        @Override
        public void onMessage(String message) {
            try {
                if (remoteEndpointBasic != null) {
                    remoteEndpointBasic.sendText(message);
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

害羞我就不演示了,其它這些在Tomcat目錄下的examples都能找到

 

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved