您的位置:首页 > 移动开发 > Android开发

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)连接管理类

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。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: