Websocket SSL加密之android端(带重连)

最近在开发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;
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值