利用websocket實現android消息推送

jopen 11年前發布 | 126K 次閱讀 Android開發 移動開發 WebSocket

    前段時間做一個項目,需要android客戶端作為管理工具與web服務器后臺實時交互,想了很多方法,包括androidpn、openfire+smack、xmpp協議,要么太繁瑣,要么無法滿足實時性。想來還是用socket,經人提醒想到了websocket。


    websocket協議是近些年隨html5發展而誕生的,主要用于解決web服務器與客戶端無法雙向交互的問題。如今已經被W3C收入標準協議。

    服務器支持:tomcat、jetty的最新版本都已支持websocket;如果不想更換現有服務器,也可用spring4.0作為替代。據說新版本的jre將收入websocket類,沒具體接觸。
</div>

    客戶端支持:目前的主流瀏覽器都已經實現了websocket,但由于前期協議版本變化太快,很多廠商沒有跟上。android默認瀏覽器就不支持websocket,IE也直到IE10才支持。


    網上已有通過html實現websocket client的例子,這里我們用java實現客戶端連接。廢話不說,上Demo:


1.服務器端

服務器用了tomcat 7.0,直接使用tomcat的websocket實現

1)連接管理類

import java.io.IOException;
import java.nio.CharBuffer;
import java.util.ArrayList;
import java.util.List;
import org.apache.catalina.websocket.MessageInbound;
import org.apache.catalina.websocket.WsOutbound;

public class MessageCenter { private static MessageCenter instance = new MessageCenter();

private List<MessageInbound>        socketList;

private MessageCenter()
{
    this.socketList = new ArrayList<MessageInbound>();
}

public static MessageCenter getInstance()
{
    return instance;
}

public void addMessageInbound(MessageInbound inbound)
{
    socketList.add(inbound);
}

public void removeMessageInbound(MessageInbound inbound)
{
    socketList.remove(inbound);
}

public void broadcast(CharBuffer msg) throws IOException
{
    for (MessageInbound messageInbound : socketList)
    {
        CharBuffer buffer = CharBuffer.wrap(msg);
        WsOutbound outbound = messageInbound.getWsOutbound();
        outbound.writeTextMessage(CharBuffer.wrap("broadcasting:" + msg));
        // outbound.writeTextMessage(buffer);
        outbound.flush();
    }
}

}</pre></div>


2)消息入口類

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.util.Date;

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

public class MyMessageInbound extends MessageInbound {

@Override
protected void onBinaryMessage(ByteBuffer arg0) throws IOException {
    // TODO Auto-generated method stub

}

@Override
protected void onTextMessage(CharBuffer msg) throws IOException {
    System.out.println("Received:"+msg);
    MessageCenter.getInstance().broadcast(msg);

}

@Override
protected void onClose(int status) {
    System.out.println("close:"+new Date());
    MessageCenter.getInstance().removeMessageInbound(this);
    super.onClose(status);
}

@Override
protected void onOpen(WsOutbound outbound) {
    System.out.println("open :"+new Date());
    super.onOpen(outbound);
    MessageCenter.getInstance().addMessageInbound(this);
}

}</pre>
</div>

3)Websocket servlet

import javax.servlet.http.HttpServletRequest;

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

public class MeWebSocketServlet extends WebSocketServlet {

private static final long serialVersionUID = -7178893327801338294L;

@Override
protected StreamInbound createWebSocketInbound(String subProtocol, HttpServletRequest request)
{
    System.out.println("##########client login#########");
    return new MeMessageInbound();
}

}</pre>
</div>

4)添加servlet到web.xml

        < servlet>
               < servlet-name> android</ servlet-name >
               < servlet-class> MyWebSocketServlet </servlet-class >
        </ servlet>
        < servlet-mapping>
               < servlet-name> android</ servlet-name >
               < url-pattern> *.do</ url-pattern >
        </ servlet-mapping>


2.客戶端

    客戶端使用java實現websocket client,

    網上有人實現了Java-websocket:https://github.com/TooTallNate/Java-WebSocket 可以取得源碼,用maven編譯。

    最新jar包下載地址:


    引用jar包后,實現簡單消息連接:

import java.net.URI;
import java.net.URISyntaxException;

import org.java_websocket.client.WebSocketClient; import org.java_websocket.drafts.Draft; import org.java_websocket.drafts.Draft_10; import org.java_websocket.drafts.Draft_17; import org.java_websocket.framing.Framedata; import org.java_websocket.handshake.ServerHandshake;

/* This example demonstrates how to create a websocket connection to a server. Only the most important callbacks are overloaded. / public class ExampleClient extends WebSocketClient {

    public ExampleClient( URI serverUri , Draft draft ) {
            super( serverUri, draft );
    }

    public ExampleClient( URI serverURI ) {
            super( serverURI );
    }

    @Override
    public void onOpen( ServerHandshake handshakedata ) {
            System.out.println( "opened connection" );
            // if you plan to refuse connection based on ip or httpfields overload: onWebsocketHandshakeReceivedAsClient
    }

    @Override
    public void onMessage( String message ) {
            System.out.println( "received: " + message );
    }

    @Override
    public void onFragment( Framedata fragment ) {
            System.out.println( "received fragment: " + new String( fragment.getPayloadData().array() ) );
    }

    @Override
    public void onClose( int code, String reason, boolean remote ) {
            // The codecodes are documented in class org.java_websocket.framing.CloseFrame
            System.out.println( "Connection closed by " + ( remote ? "remote peer" : "us" ) );
    }

    @Override
    public void onError( Exception ex ) {
            ex.printStackTrace();
            // if the error is fatal then onClose will be called additionally
    }

    public static void main( String[] args ) throws URISyntaxException {
            ExampleClient c = new ExampleClient( new URI( "ws://localhost:8080/myweb/android.do" ), new Draft_17() ); 
            c.connect();
    }

}</pre></div>

注意,連接中使用的new Draft_17()就是使用的協議version,Tomcat 7.0的協議版本需要高于Draft_17。


總結websocket的利弊

優點:

與socket相比,可以節省額外的端口占用,直接使用一個公網域名訪問。另外協議對報文的流量消耗做了優化。


缺點:

畢竟websocket底層也是socket連接,因而當大并發用戶連接時目測會消耗較多資源。


參考:


來自:http://blog.csdn.net/chifengxin/article/details/14521093

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!