利用websocket实现android消息推送

  前段时间做一个项目,需要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)连接管理类
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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();
         }
     }
}

2)消息入口类
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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 );
     }
}

3)Websocket servlet
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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();
     }
 
}

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包后,实现简单消息连接:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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();
         }
 
}
注意,连接中使用的 new  Draft_17()就是使用的协议version,Tomcat 7.0的协议版本需要高于Draft_17。

总结websocket的利弊
优点:
与socket相比,可以节省额外的端口占用,直接使用一个公网域名访问。另外协议对报文的流量消耗做了优化。

缺点:
毕竟websocket底层也是socket连接,因而当大并发用户连接时目测会消耗较多资源。

参考:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值