最近在开发Android手机端的websocket通信,用到了ssl加密。由于网上相关信息较少,而且大多较为杂乱,因此,就相关知识进行再次整理,希望对大家有用。
1、WebSocket(带重连)
普通Android端WebSocket,不必多说,写一类继承jar包中的WebSocketClient,然后依次调用该类的构造函数如:new WebSocketUtils()、链接函数:connectBlocking()完成连接即可与服务端进行通信。然而很多应用,都需要考虑到断开重连的问题,因此,在继承WebSocketClient的基础上需要自己去重新设计新类调用api进行断开时的重连。
对于重连要特别说明一个问题,connectBlocking()是只有当前类对象的线程对象为null,才会开了一个线程去做通信链接,而closeBlocking()只会关闭端口,不会结束当前对象因调用connectBlocking()建立的线程。因此,不能使用connectBlocking()和closeBlocking()配合作重连功能。正确的重连设计是要调用closeBlocking()关闭原来的链接并重新new一个对象调用connectBlocking()进行链接。
2、SSL加密
SSL加密通信的过程主要有三个部分,分别是证书读取、创建并初始化证书和信任库工厂以及//创建并初始化SSLContext实例。具体代码示例如下:
//证书读取
FileInputStream input = new FileInputStream(m_creditpath);
KeyStore ks = KeyStore.getInstance("bks");
ks.load(input,m_password.toCharArray());
input.close();
//创建并初始化证书和信任库工厂
KeyManagerFactory kmfact = KeyManagerFactory.getInstance("SunX509");
TrustManagerFactory tmfact = TrustManagerFactory.getInstance("X509");
kmfact.init(ks,m_password.toCharArray());
tmfact.init(ks);
KeyManager[] kms = kmfact.getKeyManagers();
TrustManager[] tms = tmfact.getTrustManagers();
//创建并初始化SSLContext实例
SSLContext sslContext = null;
sslContext = SSLContext.getInstance("SSL");
sslContext.init(kms, tms, null);
SSLSocketFactory factory = sslContext.getSocketFactory();
如果不需要证书,只需要信任库工厂即可,因此,SSLContext实例初始化为:
sslContext.init(null, new TrustManager[]{new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
// TODO Auto-generated method stub
return null;
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
// TODO Auto-generated method stub
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
// TODO Auto-generated method stub
}
}}, new SecureRandom());
3、带SSL加密的WebSocket
只需在调用继承jWebSocketClient的类构造函数和链接函数之间加入SSL加密的三部分,并调用WebSocketClient类的继承对象的setSocket函数即可。即:
m_sock.setSocket(factory.createSocket(m_des.getHost(),m_des.getPort()));
以上所有示例代码如下:
package WebSocket;
import java.net.URI;
import java.util.Map;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft;
import org.java_websocket.handshake.ServerHandshake;
import Protocol.ProtocolManager;
import android.util.Log;
public class WebSocketUtils extends WebSocketClient {
private static final String TAG = WebSocketUtils.class.getSimpleName();
private ProtocolManager m_callback = null;
private volatile boolean m_isopened = false;
public WebSocketUtils(URI serverUri, Draft protocolDraft, Map<String, String> httpHeaders, int connectTimeout) {
super(serverUri, protocolDraft, httpHeaders, connectTimeout);
}
@Override
public void onOpen(ServerHandshake serverHandshake) {// 连接成功
Log.i(TAG, "---onOpen---");
m_isopened = true;
}
@Override
public void onMessage(String payload) {
if(null!=m_callback && null!=payload){
m_callback.dealData(payload);
}
}
@Override
public void onError(Exception e) {
if(null != m_callback)
m_isopened = false;
}
@Override
public void onClose(int arg0, String arg1, boolean arg2) {
// TODO Auto-generated method stub
Log.i(TAG, "websocket is closed!");
m_isopened = false;
}
public ProtocolManager getM_callback() {
return m_callback;
}
public void setM_callback(ProtocolManager m_callback) {
this.m_callback = m_callback;
}
public boolean isM_isopened() {
return m_isopened;
}
public void setM_isopened(boolean m_isclosed) {
this.m_isopened = m_isclosed;
}
}
package WebSocket;
import java.net.URI;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import org.java_websocket.drafts.Draft_17;
import android.util.Log;
import Protocol.ProtocolManager;
public class WebSocketHandler extends TimerTask{
private WebSocketUtils m_sock = null;
private static WebSocketHandler m_sockhandler = null;
private ProtocolManager m_callback = null;
private static final String TAG = WebSocketHandler.class.getSimpleName();
private URI m_des = null;
private Draft_17 m_draft = null;
private int m_outtime;
private volatile boolean m_iscon = false;
private Timer m_timer;
public synchronized static WebSocketHandler getInstance(){
if(null == m_sockhandler)
m_sockhandler = new WebSocketHandler();
return m_sockhandler;
}
public void onCreate(){
m_iscon = false;
if(null == m_des || null == m_draft)
return ;
if(null == m_sock){
try{
m_sock = new WebSocketUtils(m_des, m_draft, null, m_outtime);
//创建并初始化SSLContext实例
SSLContext sslContext = null;
sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
// TODO Auto-generated method stub
return null;
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
// TODO Auto-generated method stub
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
// TODO Auto-generated method stub
}
}}, new SecureRandom());
SSLSocketFactory factory = sslContext.getSocketFactory();
//设置websocket为ssl加密
m_sock.setSocket(factory.createSocket(m_des.getHost(),m_des.getPort()));
if(m_sock.connectBlocking())
m_iscon = true;
else{
Log.e(TAG, "websocket connect fail");
}
}catch(Exception e){
e.printStackTrace();
}
}
if(null == m_sock || null == m_callback)
return ;
m_sock.setM_callback(m_callback);
if(null == m_timer){
m_timer = new Timer(true);
m_timer.schedule(m_sockhandler, 100, 3000);
Log.i(TAG,"timer init success!");
}
}
public boolean isM_iscon() {
return m_iscon;
}
public void setM_iscon(boolean m_iscon) {
this.m_iscon = m_iscon;
}
public void setParameter(URI p_uri, Draft_17 p_draft, int p_outtime, ProtocolManager p_callback){
if(null == p_uri || null == p_draft || null == p_callback)
return ;
m_des = p_uri;
m_draft = p_draft;
m_outtime = p_outtime;
m_callback = p_callback;
}
public boolean sendMessage(String p_data){
if(null == p_data)
return false;
if(m_iscon){
try{
m_sock.send(p_data);
return true;
}catch(Exception e){
Log.e(TAG, "NotYetConnectedException");
return false;
}
}else
return false;
}
public synchronized void reConnect(){
if(null == m_sock){
onCreate();
}
if(!m_iscon){
Log.e(TAG, "websocket reconnect fail");
return ;
}
m_callback.setM_keepalive(0);
}
@Override
public void run() {
// TODO Auto-generated method stub
if(null != m_callback){
m_iscon = m_sock.isM_isopened();
if(m_callback.getM_keepalive() < 3 && m_iscon){
m_callback.addM_keepalive();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date curDate = new Date(System.currentTimeMillis());
Log.i(TAG, curDate.toString());
sendMessage(m_callback.createKeepalive(format.format(curDate)));
}else{
try {
if(m_iscon)
m_sock.closeBlocking();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return ;
}
m_sock = null;
Log.i(TAG, "websocket connect " + m_callback.getM_keepalive() + " m_iscon: " + m_iscon);
reConnect();
}
}
}
public void destroy(){
m_sock.close();
m_sock = null;
}
}