1、快速使用
项目中的使用,以github的开源库org.java-websocket:Java-WebSocket:1.3.8为例,并且封装了工具类,快速上手。
1、org.java-websocket:Java-WebSocket的github地址:https://github.com/TooTallNate/Java-WebSocket
2、我封装的工具类WebSocketUtils.java的代码(下面有使用和讲解),思想是这样的:
一、重连机制。代码中有备注,在close()中重连。
二、心跳机制。工具类中,我是通过Observable.interval定时执行,10秒钟一次心跳。
三、后台返回的消息和给后台发送消息。在onMessage()中返回,和后台约定需要的数据,发送数据是通过sendMessage(),也是和后台约定好数据格式就好。
public class WebSocketUtils {
private String TAG = "web_socket";
private static WebSocketUtils instance = null;
WebSocketClient client;
//转成的要操作的数据
URI uri;
//后台连接的url
String address = "ws://114.55.103.198:8989/";
//连接是否关闭,用于判断是主动关闭还是断开,断开需要重连
boolean isHandClose;
//记录心跳重联的次数
int reconnectTimes;
//心跳timer
Disposable timerHeart;
//重连timer
Disposable timer;
//懒加载单例模式,synchronized确保线程安全。
// 适合没有多线程频繁调用的情况,多线程频繁调用的时候,可以用双重检查锁定DCL、静态内部类、枚举 等方法,文章后面会详细介绍。
public static synchronized WebSocketUtils getInstance() {
if (instance == null) {
instance = new WebSocketUtils();
}
return instance;
}
public void initSocket() {
if (null != client && client.isOpen()) {
EventBusUtils.post(new EventBusUtils.EventMessage(EVENT_WEB_SOCKET_CONNECT_SUCCESS, "登录成功!", ""));
return;
}
isHandClose = false;
startSocket();
}
public void startSocket() {
try {
uri = new URI(address);
} catch (URISyntaxException e) {
e.printStackTrace();
}
if (null == client || !client.isOpen()) {
client = new WebSocketClient(uri) {
@Override
public void onOpen(ServerHandshake serverHandshake) {
reconnectTimes = 0;
if (timer != null) {
timer.dispose();
}
//socket连接成功,通过eventbus通知房间,用户可以加入房间了
EventBusUtils.post(new EventBusUtils.EventMessage(EVENT_WEB_SOCKET_CONNECT_SUCCESS, "连接成功!", ""));
LogUtils.eTag(TAG, "连接成功");
registerWebSocket();
//10秒钟进行一次心跳,防止异常断开
timerHeart = Observable.interval(10, TimeUnit.SECONDS).subscribe(new Consumer<Long>() {
@Override
public void accept(Long aLong) throws Exception {
JSONObject jsonObject = new JSONObject();
jsonObject.put("type", "ping");
sendMessage(jsonObject.toString());
}
});
}
@Override
public void onMessage(String s) {
//后台返回的消息
EventBusUtils.post(new EventBusUtils.EventMessage(EVENT_WEB_SOCKET_RECEIVE_SUCCESS, "收到消息!", s));
LogUtils.eTag(TAG, "收到消息", s);
}
@Override
public void onClose(int i, String s, boolean b) {
if (isHandClose) {
EventBusUtils.post(new EventBusUtils.EventMessage(EVENT_WEB_SOCKET_CONNECT_SUCCESS_BY_HAND, "主动关闭成功!", s));
LogUtils.eTag(TAG, "主动关闭成功", s);
reconnectTimes = 0;
if (timer != null) {
timer.dispose();
}
if (timerHeart != null) {
timerHeart.dispose();
}
} else {
//非正常关闭进行重连,重连每次两秒,最多十次
timer = Observable.timer(2, TimeUnit.SECONDS).subscribe(new Consumer<Long>() {
@Override
public void accept(Long aLong) throws Exception {
LogUtils.eTag(TAG, "重连");
reconnectTimes = reconnectTimes + 1;
startSocket();
}
});
//重联超过十次没成功,结束重连
if (reconnectTimes > 10) {
EventBusUtils.post(new EventBusUtils.EventMessage(EVENT_WEB_SOCKET_CLOSE_SUCCESS, "关闭成功!", s));
LogUtils.eTag(TAG, "关闭成功", s);
reconnectTimes = 0;
if (timer != null) {
timer.dispose();
}
if (timerHeart != null) {
timerHeart.dispose();
}
}
}
}
@Override
public void onError(Exception e) {
EventBusUtils.post(new EventBusUtils.EventMessage(EVENT_WEB_SOCKET_ERROR, "出现错误!", ""));
LogUtils.eTag(TAG, "出现错误", e.getMessage());
}
};
client.connect();
}
}
//向服务器发送消息
public void sendMessage(String s) {
if (client == null || client.isConnecting() || client.isClosed() || !client.isOpen()) {
LogUtils.eTag(TAG, "未建立实时通信");
return;
}
try {
client.send(s);
LogUtils.eTag(TAG, "发送消息:", s);
} catch (Exception e) {
e.printStackTrace();
startSocket();
}
}
//关闭socket
public void closeSocket() {
isHandClose = true;
if (client != null) {
client.close();
client = null;
}
}
//向服务器发送初始化信息
void registerWebSocket() {
JSONObject jsonObject = new JSONObject();
jsonObject.put("type", "init");
jsonObject.put("token", MyApplication.getInstance().getToken());
sendMessage(jsonObject.toString());
}
//和服务器约定的传递的参数
public void sendData(String type, String room_id) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("type", type);
jsonObject.put("token", MyApplication.getInstance().getToken());
jsonObject.put("room_id", room_id);
sendMessage(jsonObject.toString());
}
}
3、工具类的使用:
一、在需要用的地方初始化 , WebSocketUtils.getInstance().initSocket()
二、需要传递给后台的数据,举例: WebSocketUtils.getInstance().sendData(“setRoomManager”, id, user_id)。sendData()函数的参数根据情况自己配置,和后台约定好就行。
三、结束使用websocket的时候调用, WebSocketUtils.getInstance().closeSocket()
详细讲解:
把这篇文章放到语音直播间分类,是因为语音直播间刚刚用到,而且端对端的实时通信用websocket节省带宽和性能。Android与服务器的通信方式主要是两种:一是Http通信,一是Socket通信。两者的最大差异在于,http连接使用的是“请求—响应方式”,即在请求时建立连接通道,当客户端向服务器发送请求后,服务器端才能向客户端返回数据。而Socket通信则是在双方建立起连接后就可以直接进行数据的传输,在连接时可实现信息的主动推送,而不需要每次由客户端想服务器发送请求。