Android 使用Websocket
2015-10-26 13:17
471 查看
1.Websocket背景与功能简介
传统的Android网络请求无法适应信息变化频繁的应用,比如金融证券的实时信息,Web 导航应用中的地理位置获取,社交网络的实时消息推送等。
传统的请求-响应模式的 Web 开发在处理此类业务场景时,通常采用实时通讯方案,常见的是:
轮询,原理简单易懂,就是客户端通过一定的时间间隔以频繁请求的方式向服务器发送请求,来保持客户端和服务器端的数据同步。问题很明显,当客户端以固定频率向服务器端发送请求时,服务器端的数据可能并没有更新,带来很多无谓请求,浪费带宽,效率低下。
在此背景下,Websocket应用而生,WebSocket 是 HTML5 一种新的协议。它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯,它建立在 TCP 之上,同 HTTP 一样通过 TCP 来传输数据,但是它和 HTTP 最大不同是:
WebSocket 是一种双向通信协议,在建立连接后,WebSocket 服务器和 Browser/Client Agent 都能主动的向对方发送或接收数据,就像 Socket 一样;
WebSocket 需要类似 TCP的客户端和服务器端通过握手连接,连接成功后才能相互通信。
相对于传统 HTTP 每次请求-应答都需要客户端与服务端建立连接的模式,WebSocket 是类似 Socket 的 TCP 长连接的通讯模式,一旦 WebSocket 连接建立后,后续数据都以帧序列的形式传输。在客户端断开 WebSocket 连接或 Server 端断掉连接前,不需要客户端和服务端重新发起连接请求。在海量并发及客户端与服务器交互负载流量大的情况下,极大的节省了网络带宽资源的消耗,有明显的性能优势,且客户端发送和接受消息是在同一个持久连接上发起,实时性优势明显。
2.Websocket代码实现
2.1服务端
服务器用了tomcat 7.0,直接使用tomcat的websocket实现
1)连接管理类
2)消息入口类
3)Websocket servlet
4)添加servlet到web.xml
2.2客户端
客户端使用java实现websocket client,网上有人实现了Java-websocket:
https://github.com/TooTallNate/Java-WebSocket 可以取得源码,用maven编译。
注意,连接中使用的new Draft_17()就是使用的协议version 17(RFC 6455),Tomcat 7.0使用的协议版本为RFC 6455。
传统的Android网络请求无法适应信息变化频繁的应用,比如金融证券的实时信息,Web 导航应用中的地理位置获取,社交网络的实时消息推送等。
传统的请求-响应模式的 Web 开发在处理此类业务场景时,通常采用实时通讯方案,常见的是:
轮询,原理简单易懂,就是客户端通过一定的时间间隔以频繁请求的方式向服务器发送请求,来保持客户端和服务器端的数据同步。问题很明显,当客户端以固定频率向服务器端发送请求时,服务器端的数据可能并没有更新,带来很多无谓请求,浪费带宽,效率低下。
在此背景下,Websocket应用而生,WebSocket 是 HTML5 一种新的协议。它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯,它建立在 TCP 之上,同 HTTP 一样通过 TCP 来传输数据,但是它和 HTTP 最大不同是:
WebSocket 是一种双向通信协议,在建立连接后,WebSocket 服务器和 Browser/Client Agent 都能主动的向对方发送或接收数据,就像 Socket 一样;
WebSocket 需要类似 TCP的客户端和服务器端通过握手连接,连接成功后才能相互通信。
相对于传统 HTTP 每次请求-应答都需要客户端与服务端建立连接的模式,WebSocket 是类似 Socket 的 TCP 长连接的通讯模式,一旦 WebSocket 连接建立后,后续数据都以帧序列的形式传输。在客户端断开 WebSocket 连接或 Server 端断掉连接前,不需要客户端和服务端重新发起连接请求。在海量并发及客户端与服务器交互负载流量大的情况下,极大的节省了网络带宽资源的消耗,有明显的性能优势,且客户端发送和接受消息是在同一个持久连接上发起,实时性优势明显。
2.Websocket代码实现
2.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(); } } }
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); } }
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 MyMessageInbound(); } }
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.2客户端
客户端使用java实现websocket client,网上有人实现了Java-websocket:
https://github.com/TooTallNate/Java-WebSocket 可以取得源码,用maven编译。
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.connectBlocking(); c.send("handshake"); } }
注意,连接中使用的new Draft_17()就是使用的协议version 17(RFC 6455),Tomcat 7.0使用的协议版本为RFC 6455。
相关文章推荐
- 调用系统自带浏览器的方法
- ActiveAndroid的建表跟踪
- Android消息通信之无所不能的第三方开源项目EventBus
- android开发游记:自定义实现图片轮播器和启动页面滚动
- android底层开发入门(2)-git与repo
- android intent和intent action大全
- android源码编译出错(5)
- Android Studio导入第三方类库的方法
- Android多媒体编程——图片的大小计算
- Mac下 android 模拟器/真机 host修改
- Android Activity之 setContentView()总结
- Android DEX安全攻防战
- Android APK加壳技术方案【2】
- android sdk 下的JSON解析
- Android APK加壳技术方案【1】
- Volley android 多key 多File 文件上传,目前只实现了两个key,实现多key请自己改
- Android中ListView Item布局优化技巧
- Android SQLite的建立
- Android Studio 利用Gradle打包SDK jar文件
- [Android开发从零开始].1.Android开发环境搭建