Websocket全講解。跨平臺的通訊協議 !!基於websocket的高併發即時通訊服務器開發

原文地址:http://www.cnblogs.com/lilinxuan/p/3759744.html


本博文,保證不用裝B的話語和太多專業的語言,保證簡單易懂,只要懂JAVAEE開發的人都可以看懂。 本博文發表目的是,目前網上針對Websocket的資料太散亂,導致初學者的知識體系零零散散,學習困難加大。本博加以整理,並且實踐。

所用核心技術選型:

Tomcat + Spring 4.0.3 + Mongodb(高併發數據庫)

+ SpringQueue(消息隊列)+ ActiveMQ (消息隊列)

+ Spring-data-Mongo + Servlet 3.0

+Spring-Websocket

+ Maven


注:以下Websocket 均省略成 WB


先說Websocket 的原理。 Websocket 是全雙工通訊(說白了就是倆都可以通訊,服務器也可以給客戶端發消息,客戶端也能給服務器發消息)。也是基於TCP的,效率是很高的,首先這個技術的底層選用,就決定了完全可以用wb這個技術做高併發應用,而且開發非常快!!代碼非常簡單!!最重要的是穩定性,擴展性等等都有保證,等會兒說爲什麼說都有保證。


WB 不同於TCP的三次握手。  WB是先進行一次HTTP請求,這個請求頭不同於普通HTTP請求,等會貼出來講解。然後服務器開始辨認請求頭,如果是WB的請求頭,則開始進行普通的TCP連接,即三次握手(不懂的TCP的,出門百度)。如果不是WB的HTTP請求頭,那就是按普通的HTTP請求處理。


流程梳理: HTTP特殊請求(有個特殊的頭) ---- 》 服務請接收判斷 ----- 》 認出來了,確實是WB請求頭,開啓TCP 三次握手,建立連接後,和TCP一樣了就------》沒有認出來,不是WB的請求頭,按普通HTTP請求處理。 


很清楚了吧。這是個基礎,先理解了,下面寫程序纔好搞。下面這段是Webscoket的請求頭。 GET請求

複製代碼
GET ws://localhost:12345/websocket/test.html HTTP/1.1
 Origin: http://localhost
 Connection: Upgrade
 Host: localhost:12345
 Sec-WebSocket-Key: JspZdPxs9MrWCt3j6h7KdQ==  //主要這個字段,這個叫“夢幻字符串”,這個加密規則可以去百度,是有規則的。這個也是個密鑰,只有有這個密鑰 服務器才能通過解碼 認出來,哦~這是個WB的請求,我要建立TCP連接了!!!如果這個字符串沒有按照加密規則加密,那服務端就認不出來,就會認爲這整個協議就是個HTTP請求。更不會開TCP。其他的字段都可以隨便設置,但是這個字段是最重要的字段,標識WB協議的一個字段。
 Upgrade: websocket 
Sec-WebSocket-Version: 13
複製代碼

 


下面這段是服務端迴應消息:

複製代碼
HTTP/1.1 101 Web Socket Protocol Handshake
 WebSocket-Location: ws://localhost:12345/websocket/test.php
 Connection: Upgrade
 Upgrade: websocket
 Sec-WebSocket-Accept: zUyzbJdkVJjhhu8KiAUCDmHtY/o= //這個字段,叫“夢幻字符串”,和上面那個夢幻字符串作用一樣。不同的是,這個字符串是要讓客戶端辨認的,客戶端拿到後自動解碼。並且辨認是不是一個WB請求。然後進行相應的操作。這個字段也是重中之重,不可隨便修改的。加密規則,依然是有規則的,可以去百度一下。
 WebSocket-Origin: http://localhost
複製代碼

 


好了,一去一回的HTTP請求, 如果他們的夢幻字符串都對上了,客戶端服務端都確定是一次WB請求了。。那就開始建立TCP連接了。


關於Tcp編程,爲什麼沒有選用Netty或者Mina框架,而選用以上的技術。 其實我感覺還是他們太複雜。並且,我們用Netty的話,集羣規則,負載均衡,JVM優化都需要自己做。集羣規則,負載均衡這塊兒,就是另一個大的研究方向,一個人根本搞不下來。

不如放在容器裏。比如Tomcat,你要真嫌棄Tomcat太低端。換Jboss也不是不行,他們都做了N年的優化和開發,穩定性絕對OK,集羣規則,負載均衡,JVM等等都有現成的解決方案,還有其他的一些優化 ,可以說世界頂尖。滿足你的高併發一點問題都沒。


不要重複造輪子!!別人(JBoss)的集羣規則好,負載均衡穩定,就用就是了!!!!所以,小的WB應用推薦tomcat,高併發的WB應用,推薦Jboss。並且合理設置集羣規則,合理配置負載均衡,合理優化JVM,我保證,滿足你的高併發websocket需求完全不是問題。。

加上我們的數據庫選型和消息隊列,都是爲高併發添火的技術,所以代碼寫的乾淨的話,高併發完全不是問題。不用糾結,WB的效率如何,集羣怎麼做~負載均衡是不是要自己寫。。答案是NO。 解決方案是 用高端點的應用容器!!

這就是WB和TCP比的優勢!!他可以在容器裏搞~ 集羣方案,負載均衡方案都是人家做好的。

原生的TCP協議,你必須自己去解決這些問題。這真是一個大問題,想想就知道了,單單集羣這塊兒,有幾個能做的好的。。

先貼pom.xml

複製代碼
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mendao</groupId>
    <artifactId>websocket</artifactId>
    <packaging>war</packaging>
    <version>1.0.0</version>
    <description>門道的即時通訊服務器</description>

    <properties>
        <!--Fast Json-->
        <fastjson.version>1.1.39</fastjson.version>

        <!-- Servlet 版本號 -->
        <servlet.version>3.1.0</servlet.version>

        <!-- spring版本號 3.2.8.RELEASE  -->
        <spring.version>4.0.3.RELEASE</spring.version>

        <!-- Hibernate版本號 4.3.5.Final -->
        <hibernate.version>3.6.10.Final</hibernate.version>

        <!-- mysql版本號 -->
        <mysql.version>5.1.30</mysql.version>

        <!--logback-->
        <logback.version>1.1.2</logback.version>

        <!-- xmemcached 版本號 -->
        <xmemcached.version>2.0.0</xmemcached.version>

        <!--Activemq -->
        <activemq.version>5.7.0</activemq.version>

        <!-- 高速序列化框架 -->
        <kryo.version>2.23.0</kryo.version>

        <!--tomcat-->
        <tomcat.version>8.0.5</tomcat.version>
    </properties>

    <dependencies>
        <!-- 高性能 序列化框架 -->
        <dependency>
            <groupId>com.esotericsoftware.kryo</groupId>
            <artifactId>kryo</artifactId>
            <version>${kryo.version}</version>
        </dependency>
        <!--異步消息隊列-->
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-core</artifactId>
            <version>${activemq.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.xbean</groupId>
            <artifactId>xbean-spring</artifactId>
            <version>3.17</version>
        </dependency>


        <!-- 必須包 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>${servlet.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.annotation</groupId>
            <artifactId>jsr250-api</artifactId>
            <version>1.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.persistence</groupId>
            <artifactId>persistence-api</artifactId>
            <version>1.0.2</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.7.4</version>
        </dependency>
        <dependency>
            <groupId>xerces</groupId>
            <artifactId>xercesImpl</artifactId>
            <version>2.11.0</version>
        </dependency>
        <dependency>
            <groupId>antlr</groupId>
            <artifactId>antlr</artifactId>
            <version>2.7.7</version>
        </dependency>
        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6.1</version>
        </dependency>

        <!-- spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-websocket</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jms</artifactId>
            <version>${spring.version}</version>
        </dependency>


        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-mongodb</artifactId>
            <version>1.4.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>1.2.1.RELEASE</version>
        </dependency>

        <!-- mysql驅動包 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>

        <!-- FastJson 來處理JSON數據 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastjson.version}</version>
        </dependency>

        <!-- logback-->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>${logback.version}</version>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>${logback.version}</version>
        </dependency>

        <!-- xmemcached 緩存服務器 -->
        <dependency>
            <groupId>com.googlecode.xmemcached</groupId>
            <artifactId>xmemcached</artifactId>
            <version>${xmemcached.version}</version>
        </dependency>

        <!--Common 系列-->
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3</version>
        </dependency>
        <!--加密解密,編碼解碼-->
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.9</version>
        </dependency>
        <dependency>
            <groupId>commons-httpclient</groupId>
            <artifactId>commons-httpclient</artifactId>
            <version>3.1</version>
        </dependency>


        <!--Tomcat 環境支持-->
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-websocket</artifactId>
            <version>${tomcat.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-coyote</artifactId>
            <version>${tomcat.version}</version>
            <scope>provided</scope>
        </dependency>

    </dependencies>

    <build>
        <finalName>ROOT</finalName>
        <plugins>
            <!-- 使用JDK1.7編譯java源文件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>


            <!-- 使用UTF-8編碼資源文件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <version>2.5</version>
                <configuration>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>

            <!--WAR 打包插件-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>
複製代碼

 

然後,開始進入正題。web.xml配置。我貼上我的配置。

複製代碼
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee" xmlns:javaee="http://java.sun.com/xml/ns/javaee"
         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javeee/web-app_3_0.xsd"
         version="3.0"> <!--關鍵點!servlet要是3.0不能再是2.5了-->

    <welcome-file-list>
        <welcome-file>welcome.html</welcome-file>
    </welcome-file-list>

    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextClass</param-name>
            <param-value>
                org.springframework.web.context.support.AnnotationConfigWebApplicationContext
            </param-value>
        </init-param>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                com.mendao.config.WebConfig <!--關鍵點!我們需要用spring的全註解配置方式來配置websocket,所以這塊兒需要指向你的對應的類-->
            </param-value>
        </init-param>
    </servlet>

    <!-- Spring MVC -->
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern> <!--關鍵點!一旦你使用wb 就不能使用普通的springmvc裏的HTTP請求了,也就是要麼這個程序使用WB的技術要麼使用springmvc的技術,二者不可兼得!!所以WB和Springmvc必須分開程序寫-->
    </servlet-mapping>

    <!-- Spring 監聽器 -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <!--Spring Request 監聽器-->
    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>

    <!-- 編碼強轉 -->
    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>


    <!-- Spring 刷新Introspector防止內存泄露 請求多了會內存泄露,加上他就好了-->
    <listener>
        <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
    </listener>
</web-app>
複製代碼

 

web.xml沒什麼可說的了。主要點已經標註。然後貼上

com.mendao.config.WebConfig 

這個類讓大家一看究竟!!完全可以直接複製下來

複製代碼
/**
 * WebSocket 配置類
 */
@Configuration //一定不能少
@ImportResource("classpath*:/applicationContext.xml") //重要!!加載spring的其他的xml配置文件,這種方式是註解方式+xml方式 相結合的配置方式!!
@EnableWebSocket //不能少
public class WebConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {

    @Resource
    private BootstrapHandler clientHandler; //注入實例
    @Resource
    private Bootstrapnterceptor interceptor; //注入實例

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {//重要!處理器 URL地址 攔截器!! 都在這裏加入!!//等會兒帖 處理器和 攔截器的代碼        //你需要更多處理器 或者URL 都在這裏填就是了。其實一般一個就夠了,一個核心處理器做請求中轉。
        registry.addHandler(clientHandler, "/bootstrap").addInterceptors(interceptor);
    }

    // Allow serving HTML files through the default Servlet    // 完全可以無視下面的代碼    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

}
複製代碼

 

下面是BootstrapHandler 的代碼!都有註釋

複製代碼
@Service
public class BootstrapHandler implements WebSocketHandler {

    private final Logger logger = LoggerFactory.getLogger(BootstrapHandler.class);
    @Resource
    private BootstrapHandlerService bootstrapHandlerService;
    @Resource
    private Cached cached;

    /**
     * 雙工通訊 連接後 並且在這裏心跳
     *
     * @param session
     * @throws Exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        TextMessage textMessage;
        try {
            HttpHeaders headers = session.getHandshakeHeaders();
            String userAgent = headers.get("user-agent").get(0);
            logger.info("LOGIN : " + userAgent);
        //構造迴應的消息,每次連接成功後要回應消息吖!告訴客戶端已經連接成功了!消息就在這裏面構造
textMessage
= new TextMessage(“連接成功”); } catch (Exception e) { e.printStackTrace(); textMessage = new TextMessage(“連接失敗”); }      //這樣就發送給客戶端了~ 很簡單!!
session.sendMessage(textMessage); }
/** * 處理髮送過來的消息 * * @param session * @param message * @throws Exception */ @Override public void handleMessage(WebSocketSession session, WebSocketMessage message) throws Exception { try {        //如果連接成功!!這裏面會不停的接收到心跳包!! 怎麼處理~看你的了!!! 總之這個方法就是接受客戶端發來消息的方法!!!

       // message.getPayload()得到的是客戶端發來的消息,比如“你好啊!” 之類的。得到後轉成String就能處理了!
StringBuffer sb
= new StringBuffer((String) message.getPayload());        //這個是我自己寫的一個處理業務邏輯。你可以實現自己的業務邏輯
bootstrapHandlerService.handleMessage(session, sb); }
catch (Exception e) { e.printStackTrace(); logger.error(e.getMessage()); } } /** * 客戶端 異常斷開 * * @param session * @param throwable * @throws Exception */ @Override public void handleTransportError(WebSocketSession session, Throwable throwable) throws Exception { logger.info(session.getId() + " - 異常斷開連接");
//所謂異常斷開,例如:突然關閉HTML頁面等等,總之不是用戶正常關閉的!      //這個也是我自己實現的 異常處理的業務邏輯,你可以自己寫
bootstrapHandlerService.handleError(session, throwable); }
/** * 連接已經斷 開 * * @param session * @param status * @throws Exception */ @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {      //只要是斷開連接!不管是異常斷開,還是普通正常斷開,一定會進入這個方法。
String reason
= status.getReason(); if (reason == null) { reason = "客戶端 按指令正常退出"; }     
logger.info(session.getId()
+ " - 已經主動關閉連接 - 關閉碼 - " + status.getCode() + " - 緣由 -" + reason);
//其實這裏面封裝了個session.close()釋放了一些資源, 也是我自己實現的業務邏輯,你也可以自己寫! bootstrapHandlerService.connectionClose(session); }
/** * 握手成功 初始化操作在這裏面進行 * * @return */ @Override public boolean supportsPartialMessages() {       //一旦HTTP認證成功 這個方法先被調用 如果返回true 則進行上面那麼N多方法的流程。如果返回的是false就直接攔截掉了。不會調用上面那些方法了!!
//就好像個構造器一樣。這個是處理器 BootstrapHandler的構造器~
return true; } }
複製代碼


然後貼上 Interceptor 攔截器的代碼!! 實現的接口不能變!!裏面沒代碼的原因是 我實在不知道在這裏面做什麼操作,感覺我的業務是用不到這兩個方法。

複製代碼
@Service
public class Bootstrapnterceptor implements HandshakeInterceptor {

    /**
     * 握手前
     *
     * @param request
     * @param response
     * @param webSocketHandler
     * @param stringObjectMap
     * @return
     * @throws Exception
     */
    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler webSocketHandler, Map<String, Object> stringObjectMap) throws Exception {
        return true;
    }

    /**
     * 握手成功後
     *
     * @param request
     * @param response
     * @param handler
     * @param e
     */
    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler handler, Exception e) {
    }
}
複製代碼

 

 

然後我上一個HTML版的客戶端測試程序!!

複製代碼
 
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>w</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript"> 
var heartbeat_timer = 0; 
var last_health = -1; 
var health_timeout = 3000;

$(function(){
            //ws = ws_conn( "ws://211.100.41.186:9999" );
            ws = ws_conn( "ws://127.0.0.1:12345/bootstrap"); 

            $("#send_btn").click(function(){
                var msg = $("#mysendbox").val();
                alert(msg);
                alert(ws);
                ws.send(msg);
                $("#mysendbox").val("");
            });
});

function keepalive( ws ){
    var time = new Date();
    if( last_health != -1 && ( time.getTime() - last_health > health_timeout ) ){
            //此時即可以認爲連接斷開,可是設置重連或者關閉
            $("#keeplive_box").html( "服務器沒有響應." ).css({"color":"red"});
            //ws.close();
    }
    else{
        $("#keeplive_box").html( "連接正常" ).css({"color":"green"});
        if( ws.bufferedAmount == 0 ){
            ws.send( '1');        }
    }
}

//websocket function
function ws_conn( to_url ){
    to_url = to_url || "";
    if( to_url == "" ){
        return false;
    }
    
    clearInterval( heartbeat_timer );
    $("#statustxt").html("Connecting...");
    var ws = new WebSocket( to_url );
  ws.onopen=function(){
        $("#statustxt").html("connected.");    
        $("#send_btn").attr("disabled", false);
        heartbeat_timer = setInterval( function(){keepalive(ws)}, 5000 );
    }
    ws.onerror=function(){
        $("#statustxt").html("error.");
        $("#send_btn").attr("disabled", true);
        clearInterval( heartbeat_timer );
        $("#keeplive_box").html( "連接出錯." ).css({"color":"red"});
    }
    ws.onclose=function(){
        $("#statustxt").html("closed.");
        $("#send_btn").attr("disabled", true);
        clearInterval( heartbeat_timer );
        $("#keeplive_box").html( "連接已關閉." ).css({"color":"red"});
    }
    
    ws.onmessage=function(msg){
        var time = new Date();
        if( msg.data == ( '1' ) ){
            last_health = time.getTime();
            return;
        }
        
        $("#chatbox").val( $("#chatbox").val() + msg.data + "\n" );
        $("#chatbox").attr("scrollTop",$("#chatbox").attr("scrollHeight"));
    }
    
    return ws;
}
</script>
</head>

<body>


<p>web socket連接狀態:&nbsp;&nbsp;<span id="statustxt">連接中...</span></p>
<p>心跳狀態:<span id="keeplive_box">檢測中...</span></p>
<p>
  <textarea name="chatbox" id="chatbox" cols="55" rows="20" readonly="readonly"></textarea>
</p>
<p>
  <p>發送文本到Websocket服務器</p>
  <input name="mysendbox" type="text" id="mysendbox" size="50" />
  &nbsp;
  <input type="button" name="send_btn" id="send_btn" value="Send" disabled="disabled" />
  <input type="button" onclick="javascript:ws.close()" value="Close"/>
</p>
</body>
</html>
複製代碼

 

 


核心的就這麼多。

這些方法理解了,其他的,靠自己發揮想象~

對了,每個不同的連接都會有一個不同的WebSocketSession session   你可以把這個session存入一個全局的ConcurrentHashMap中!!作爲連接池!!

用的時候 用 map.get(key); 然後就能用sendMessage(); 發送給他消息了!!!

什麼時候存這個session,這就看你的業務需要了。總之每個WebSocketSession 標識一個完全不同的新的連接。客戶句柄來形容,也可以~

 

然後雖然你用上了WB 但是還是要自己做出來。心跳包~ 數據分割處理~ 等等一些基本的業務邏輯~ 什麼地方用消息隊列分發,那就要看你業務怎麼設計了。

離線消息怎麼做,可以找我私聊QQ。631768417 有不懂的也可以私聊我QQ

 

最後!!最有用的!!websocket可以做移動端 (安卓IOS等)即時通訊服務器。但是需要用到一個jar包。在github上搜索 websocket client (websocket的客戶端) 有java的實現也有object-c的實現

這個思路提供出來之後,你就知道websocket 的強大了吧。不但敏捷開發!而且跨平臺!!可以做android推送解決方案!! 當然也可以整合ios做即時通訊!!當然!!HTML更可以!因爲原生的就是HTML!!! 強大的websocket爲企業即時通訊方案提供了更好的出路!!!

 

核心已經講解!更多的發揮想象吧!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章