websocket实现android消息推送

来源:互联网 发布:算法设计最值 编辑:程序博客网 时间:2024/05/16 11:48
    前段时间做一个项目,需要android客户端作为管理工具与web服务器后台实时交互,想了很多方法,包括androidpn、openfire+smack、xmpp协议,要么太繁琐,要么无法满足实时性。想来还是用socket,经人提醒想到了websocket。

    websocket协议是近些年随html5发展而诞生的,主要用于解决web服务器与客户端无法双向交互的问题。如今已经被W3C收入标准协议。
    服务器支持:tomcat、jetty的最新版本都已支持websocket;如果不想更换现有服务器,也可用spring4.0作为替代。据说新版本的jre将收入websocket类,没具体接触。
    客户端支持:目前的主流浏览器都已经实现了websocket,但由于前期协议版本变化太快,很多厂商没有跟上。android默认浏览器就不支持websocket,IE也直到IE10才支持。
    网上已有通过html实现websocket client的例子,这里我们用java实现客户端连接。废话不说,上Demo:

1.服务器端
服务器用了tomcat 7.0,直接使用tomcat的websocket实现
1)连接管理类
[java] view plain copy
  1. import java.io.IOException;  
  2. import java.nio.CharBuffer;  
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5. import org.apache.catalina.websocket.MessageInbound;  
  6. import org.apache.catalina.websocket.WsOutbound;  
  7.   
  8. public class MessageCenter  
  9. {  
  10.     private static MessageCenter        instance           = new MessageCenter();  
  11.   
  12.     private List<MessageInbound>        socketList;  
  13.   
  14.     private MessageCenter()  
  15.     {  
  16.         this.socketList = new ArrayList<MessageInbound>();  
  17.     }  
  18.   
  19.     public static MessageCenter getInstance()  
  20.     {  
  21.         return instance;  
  22.     }  
  23.   
  24.     public void addMessageInbound(MessageInbound inbound)  
  25.     {  
  26.         socketList.add(inbound);  
  27.     }  
  28.   
  29.     public void removeMessageInbound(MessageInbound inbound)  
  30.     {  
  31.         socketList.remove(inbound);  
  32.     }  
  33.   
  34.     public void broadcast(CharBuffer msg) throws IOException  
  35.     {  
  36.         for (MessageInbound messageInbound : socketList)  
  37.         {  
  38.             CharBuffer buffer = CharBuffer.wrap(msg);  
  39.             WsOutbound outbound = messageInbound.getWsOutbound();  
  40.             outbound.writeTextMessage(CharBuffer.wrap("broadcasting:" + msg));  
  41.             // outbound.writeTextMessage(buffer);  
  42.             outbound.flush();  
  43.         }  
  44.     }  
  45. }  

2)消息入口类
[java] view plain copy
  1. import java.io.IOException;  
  2. import java.nio.ByteBuffer;  
  3. import java.nio.CharBuffer;  
  4. import java.util.Date;  
  5.   
  6. import org.apache.catalina.websocket.MessageInbound;  
  7. import org.apache.catalina.websocket.WsOutbound;  
  8.   
  9. public class MyMessageInbound extends MessageInbound {  
  10.   
  11.     @Override  
  12.     protected void onBinaryMessage(ByteBuffer arg0) throws IOException {  
  13.         // TODO Auto-generated method stub  
  14.           
  15.     }  
  16.   
  17.     @Override  
  18.     protected void onTextMessage(CharBuffer msg) throws IOException {  
  19.         System.out.println("Received:"+msg);  
  20.         MessageCenter.getInstance().broadcast(msg);  
  21.           
  22.     }  
  23.   
  24.     @Override  
  25.     protected void onClose(int status) {  
  26.         System.out.println("close:"+new Date());  
  27.         MessageCenter.getInstance().removeMessageInbound(this);  
  28.         super.onClose(status);  
  29.     }  
  30.   
  31.     @Override  
  32.     protected void onOpen(WsOutbound outbound) {  
  33.         System.out.println("open :"+new Date());  
  34.         super.onOpen(outbound);  
  35.         MessageCenter.getInstance().addMessageInbound(this);  
  36.     }  
  37. }  

3)Websocket servlet
[java] view plain copy
  1. import javax.servlet.http.HttpServletRequest;  
  2.   
  3. import org.apache.catalina.websocket.StreamInbound;  
  4. import org.apache.catalina.websocket.WebSocketServlet;  
  5.   
  6. public class MeWebSocketServlet extends WebSocketServlet  
  7. {  
  8.   
  9.     private static final long serialVersionUID = -7178893327801338294L;  
  10.   
  11.     @Override  
  12.     protected StreamInbound createWebSocketInbound(String subProtocol, HttpServletRequest request)  
  13.     {  
  14.         System.out.println("##########client login#########");  
  15.         return new MyMessageInbound();  
  16.     }  
  17.   
  18. }  

4)添加servlet到web.xml
[html] view plain copy
  1. < servlet>  
  2.        < servlet-name> android</ servlet-name >  
  3.        < servlet-class> MyWebSocketServlet </servlet-class >  
  4. </ servlet>  
  5. < servlet-mapping>  
  6.        < servlet-name> android</ servlet-name >  
  7.        < url-pattern> *.do</ url-pattern >  
  8. </ servlet-mapping>  
2.客户端
    客户端使用java实现websocket client,
    网上有人实现了Java-websocket:https://github.com/TooTallNate/Java-WebSocket 可以取得源码,用maven编译。
    最新jar包下载地址:
    http://download.csdn.net/detail/chifengxin/6524283

    引用jar包后,实现简单消息连接:
[java] view plain copy
  1. import java.net.URI;  
  2. import java.net.URISyntaxException;  
  3.   
  4. import org.java_websocket.client.WebSocketClient;  
  5. import org.java_websocket.drafts.Draft;  
  6. import org.java_websocket.drafts.Draft_10;  
  7. import org.java_websocket.drafts.Draft_17;  
  8. import org.java_websocket.framing.Framedata;  
  9. import org.java_websocket.handshake.ServerHandshake;  
  10.   
  11. /** This example demonstrates how to create a websocket connection to a server. Only the most important callbacks are overloaded. */  
  12. public class ExampleClient extends WebSocketClient {  
  13.   
  14.         public ExampleClient( URI serverUri , Draft draft ) {  
  15.                 super( serverUri, draft );  
  16.         }  
  17.   
  18.         public ExampleClient( URI serverURI ) {  
  19.                 super( serverURI );  
  20.         }  
  21.   
  22.         @Override  
  23.         public void onOpen( ServerHandshake handshakedata ) {  
  24.                 System.out.println( "opened connection" );  
  25.                 // if you plan to refuse connection based on ip or httpfields overload: onWebsocketHandshakeReceivedAsClient  
  26.         }  
  27.   
  28.         @Override  
  29.         public void onMessage( String message ) {  
  30.                 System.out.println( "received: " + message );  
  31.         }  
  32.   
  33.         @Override  
  34.         public void onFragment( Framedata fragment ) {  
  35.                 System.out.println( "received fragment: " + new String( fragment.getPayloadData().array() ) );  
  36.         }  
  37.   
  38.         @Override  
  39.         public void onClose( int code, String reason, boolean remote ) {  
  40.                 // The codecodes are documented in class org.java_websocket.framing.CloseFrame  
  41.                 System.out.println( "Connection closed by " + ( remote ? "remote peer" : "us" ) );  
  42.         }  
  43.   
  44.         @Override  
  45.         public void onError( Exception ex ) {  
  46.                 ex.printStackTrace();  
  47.                 // if the error is fatal then onClose will be called additionally  
  48.         }  
  49.   
  50.         public static void main( String[] args ) throws URISyntaxException {  
  51.                 ExampleClient c = new ExampleClient( new URI( "ws://localhost:8080/myweb/android.do" ), new Draft_17() );   
  52.                 c.connectBlocking();  
  53.                 c.send("handshake");  
  54.         }  
  55. }  
注意,连接中使用的new Draft_17()就是使用的协议version 17(RFC 6455),Tomcat 7.0使用的协议版本为RFC 6455。
总结websocket的利弊
优点:
与socket相比,可以节省额外的端口占用,直接使用一个公网域名访问。另外协议对报文的流量消耗做了优化。
缺点:
毕竟websocket底层也是socket连接,因而当大并发用户连接时目测会消耗较多资源。
参考:
Tomcat 7.0 api http://tomcat.apache.org/tomcat-7.0-doc/api/

原创粉丝点击