安卓中的Socket通信和Https通信中证书的校验方法

Socket通信与Https通信

本项目demo:DEMO
下载麻烦点下小星星,谢谢!

Part1- Socket通信

socket是一个常见的网络协议。这篇文章我们通4过个简单的聊天室的例子,来实践一下TCP和UDP在socket中的应用。以及使用Https协议的时候,我们客户端所需要的操作。

在一切开始之前,需要在mainfest.xml文件中申请网络使用权限
.
.
.

案例一:UDP聊天室

这个案例中,有两个主要的类

  • DatagramSocket:代表UDP协议的Socket,DatagramSocket本身只是码头,不维护状态,不能产生IO流,它的唯一作用就是接收和发送数据报。
  • DatagramPacket:代表数据报文,UDP传输过程中数据的载体

具体的细节在代码的备注中,代码主要分为客户端和服务器端,模拟进行通讯。

UDP服务器端代码:

package com.example.chatroom.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;

public class UdpServer {

    private InetAddress mAddress;//指定IP地址
    private int mPort = 7777; //用于指定监听的端口号
    private DatagramSocket mSocket;

    private Scanner scanner;


    public static void main(String[] args) {
        System.out.println("server is started!");
        new UdpServer().start();
    }

    public UdpServer()
    {
        try {
            mAddress = InetAddress.getLocalHost();//获取本机InetAddress实例
            mSocket = new DatagramSocket(mPort,mAddress);//构造DatagramSocket对象
            scanner = new Scanner(System.in);//获取输入
            scanner.useDelimiter("\n");
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (SocketException e) {
            e.printStackTrace();
        }

    }


    public void start() {
        while (true) {
            byte[] bytes = new byte[1024];
            DatagramPacket receivePacket = new DatagramPacket(bytes, bytes.length);//载体
            try {
                mSocket.receive(receivePacket);//收取服务器发来的信息

                InetAddress address = receivePacket.getAddress();//获取报文中的ip地址
                int port = receivePacket.getPort();//获取端口号
                byte[] data = receivePacket.getData();//获取报文中的数据
                String clientMessage = new String(data, 0, receivePacket.getLength());//用bute数组构建String对象

                System.out.println("address:" + address + "," + "port:" + port + "," + "clientMessage:" + clientMessage);

                String returnedMessage = scanner.next();//获取控制台的输入
                byte[] reruened = returnedMessage.getBytes();//转换为byte数组

                DatagramPacket sentPacket = new DatagramPacket(reruened, reruened.length, receivePacket.getSocketAddress());//构建成数据包包
                mSocket.send(sentPacket);//发送数据报

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

UDP客户端代码:

package com.example.chatroom.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;

public class UdpClient {

    private String mServerIp = "192.168.3.8";//指定要访问服务的IP
    private InetAddress mInetAddress;
    private int mServerPort = 7777;//要访问的端口号
    private DatagramSocket mSocket;
    private Scanner mScanner;

    public static void main(String[] args) {
        System.out.println("client is started!");
        new UdpClient().start();
    }

    public UdpClient()
    {
        try {
            mSocket = new DatagramSocket();
            mInetAddress = InetAddress.getByName(mServerIp);//构造InetAddress 对象
            mScanner = new Scanner(System.in);
            mScanner.useDelimiter("\n");
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }

    public void start()
    {
        while (true){
            try {
            String clientMessage = mScanner.next();//获取控制台输入的数据

            byte[] clientMessageBytes = clientMessage.getBytes();

            DatagramPacket clientPacket = new DatagramPacket(clientMessageBytes,
                    clientMessageBytes.length,mInetAddress,mServerPort);//将数据打包到DatagramPacket 中

                mSocket.send(clientPacket);//通过socket发送数据


                byte[] bytes = new byte[1024];
                DatagramPacket serverMsgPacket = new DatagramPacket(bytes,bytes.length);
                mSocket.receive(serverMsgPacket);//接收服务器发来的数据



//                InetAddress address = serverMsgPacket.getAddress();
//                int port = serverMsgPacket.getPort();
                byte[] data = serverMsgPacket.getData();
                String serverMessage = new String(data, 0, serverMsgPacket.getLength());

                System.out.println( "serverMessage:" + serverMessage);//将数据打印在控制台

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

测试结果如下:

安卓中的Socket通信和Https通信中证书的校验方法_第1张图片
安卓中的Socket通信和Https通信中证书的校验方法_第2张图片
值得注意的是, mSocket.receive()方法在没有收到数据的时候会一直处于阻塞状态。

我们可以以将客户端的代码迁移到安卓上,布局如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".UDPActivity">
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="50dp">


    <EditText
        android:id="@+id/input"
        android:layout_width="0dp"
        android:layout_weight="3"
        android:layout_height="wrap_content"
        android:text="Hello World!" />
        <Button
            android:id="@+id/send"
            android:text="发送"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="match_parent"/>
    </LinearLayout>
    <ScrollView
        android:layout_marginTop="50dp"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/message"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>


    </ScrollView>

</RelativeLayout>

就是这个样子的:
安卓中的Socket通信和Https通信中证书的校验方法_第3张图片
迁移之后,安卓端代码如下:
首先我们将消息发送的业务逻辑迁移到一个新的类中,代码和之前客户端的基本一致:

package com.example.chatroom.biz;

import android.os.Handler;
import android.os.Looper;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

public class UdpClientBiz {

    private String mServerIp = "192.168.2.101";
    private InetAddress mInetAddress;
    private int mServerPort = 7777;
    private DatagramSocket mSocket;

    private Handler mUIHandler = new Handler(Looper.getMainLooper());//将handler声明在主线程中,方便我们操作UI

//创建一个接口在进行收到消息和发生异常时候的回调
    public interface OnMessageReturnListener
    {
        void onMessageReturn(String message);
        void onError(Exception e);

    }

    public void sendMsg(final String msg, final OnMessageReturnListener onMessageReturnListener)
    {
        new Thread(){
            @Override
            public void run() {
                try {
                    //sendmessage
                    byte[] clientMessageBytes = msg.getBytes();

                    DatagramPacket clientPacket = new DatagramPacket(clientMessageBytes,
                            clientMessageBytes.length,mInetAddress,mServerPort);
                    mSocket.send(clientPacket);

                    //reciveMessage
                    byte[] bytes = new byte[1024];
                    DatagramPacket serverMsgPacket = new DatagramPacket(bytes,bytes.length);
                    mSocket.receive(serverMsgPacket);
                    final String serverMessage = new String(serverMsgPacket.getData(), 0, serverMsgPacket.getLength());

                    mUIHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            onMessageReturnListener.onMessageReturn(serverMessage);
                        }
                    });


                    System.out.println( "clientMessage:" + serverMessage);
                } catch (final IOException e) {
                    e.printStackTrace();
                    mUIHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            onMessageReturnListener.onError(e);
                        }
                    });

                }
            }
        }.start();

    }

    public UdpClientBiz()
    {
        try {
            mSocket = new DatagramSocket();
            mInetAddress = InetAddress.getByName(mServerIp);
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }


    public void destory()
    {
        if (mSocket != null)
        {
            mSocket.close();
        }
    }

}

在Activity中:

package com.example.chatroom;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import com.example.chatroom.biz.UdpClientBiz;

public class UDPActivity extends AppCompatActivity  {
    private EditText mEditText;
    private Button mButtonSend;
    private TextView mTextViewMessage;

    private UdpClientBiz udpClientBiz = new UdpClientBiz();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setTitle("UDP_CHATROOM");

        initView();

        mButtonSend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                String messages = mEditText.getText().toString();
                if (TextUtils.isEmpty(messages))
                {
                    return;
                }
                appendMessage2Content("client:"+messages);
                udpClientBiz.sendMsg(messages, new UdpClientBiz.OnMessageReturnListener() {
                    @Override
                    public void onMessageReturn(String message) {
                        appendMessage2Content("server:"+message);
                    }

                    @Override
                    public void onError(Exception e) {
                        e.printStackTrace();
                    }
                });
                mEditText.setText(" ");

            }
        });
    }

    private void appendMessage2Content(String message) {
        mTextViewMessage.append(message+"\n");
    }

    private void initView() {
        mEditText = findViewById(R.id.input);
        mButtonSend = findViewById(R.id.send);
        mTextViewMessage = findViewById(R.id.message);
    }


}


结果如下:
安卓中的Socket通信和Https通信中证书的校验方法_第4张图片

案例二:TCP聊天室

相比UDP而言,TCP就显得比较简洁。我们只需要通过ServerSocket的输入流/输出流来获取客户端/服务器发来的数据。
虽然比较简洁,但我们的这个例子却不太简单。这个案例实现的是多个客户端和服务器组成的多人聊天室。由于聊天室不是1对1的,所以需要一个消息缓存的机制,然后让服务器循环从消息池中取出消息,转发到客户端。

我们先看消息池是怎么样的:

package com.example.chatroom.tcp.server;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;

public class MessagePool {

    private static MessagePool messagePoolInstance = new MessagePool();//单例
    private LinkedBlockingQueue<String> messageQueue = new LinkedBlockingQueue();//消息队列
    private List<MessageConmingListener> msgListeners = new ArrayList<>();


    public MessagePool() {
    }



//获取单例,为例简单先不做锁
    public static MessagePool getMessagePoolInstance()
    {
        return messagePoolInstance;
    }

//发送消息的方法
    public void sendMessage(String message)
    {
        try {
            messageQueue.put(message);//将消息放入消息队列
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void start()
    {
        new Thread(){
            @Override
            public void run() {
                while (true){
                    try {
                        String msg = messageQueue.take();//从消息队列中取出消息
                        notifiMessageComing(msg);//使用观察者模式,通知客户端新消息
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
            }
        }.start();
    }

//通知客户端新的消息
    private void notifiMessageComing(String msg) {
        for (MessageConmingListener listener:msgListeners) {
            listener.onMessageComing(msg);
        }
    }

//消息监听器接口
    public interface MessageConmingListener
    {
        void onMessageComing(String message);
    }

//注册消息监听器
    public void addMessageConmingListener(MessageConmingListener messageConmingListener)
    {
        msgListeners.add(messageConmingListener);
    }
}

然后我们看服务器端:

package com.example.chatroom.tcp.server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class TCPServer {

    public void start() {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(9090);//监听9090端口
            MessagePool.getMessagePoolInstance().start();//开始从消息池中取出消息,并发出去
            while (true) {
                Socket socket = serverSocket.accept();//接收客户端的请求,并拿到存储了客户端数据的Socket对象
                System.out.println("ip:" + socket.getInetAddress().getHostAddress()
                        + ", port:" + socket.getPort() + "is online now ...");

                ClientTask clientTask = new ClientTask(socket);//给这个socket所代表的客户端注册一个ClientTask 
                MessagePool.getMessagePoolInstance().addMessageConmingListener(clientTask);//将ClientTask 加入到观察者中
                clientTask.start();

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new TCPServer().start();
    }
}

我们看看clientTask:

package com.example.chatroom.tcp.server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;

//实现了消息监听的接口,继承自Thread类
public class ClientTask extends Thread implements MessagePool.MessageConmingListener {

    private Socket mSocket;
    private InputStream inputStream;
    private OutputStream outputStream;

    public ClientTask(Socket Socket) {

        try {
            mSocket = Socket;
            inputStream = mSocket.getInputStream();
            outputStream = mSocket.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void run() {
        BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));//用BufferReader从输入流中读取数据
        try {
            String line ;

            while ((line = br.readLine())!=null)
            {
                System.out.println("read:"+line);
                //转发消息给其他客户端
                MessagePool.getMessagePoolInstance().sendMessage("port:"+mSocket.getPort()+"  message:"+line);

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

//在消息池中被回调
    @Override
    public void onMessageComing(String message) {
        try {
        //向连接到服务的客户端写数据
            outputStream.write(message.getBytes());
            outputStream.write("\n".getBytes());
            outputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

最后我们看一下客户端类:

package com.example.chatroom.tcp.client;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Scanner;

public class TCPClient {


    private Scanner mScanner;

    public TCPClient() {
        this.mScanner = new Scanner(System.in);
        mScanner.useDelimiter("\n");
    }

    public void start()
    {
        try {
            Socket socket = new Socket("192.168.2.100",9090);//访问对应ip下的端口
            InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream();

            final BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream));

            new Thread(){
                @Override
                public void run() {
                    String line = null;
                    try {

                        while ((line = br.readLine()) != null) {

                            System.out.println(line);//将受到的消息打印到控制台
                        }
                    }
                    catch (Exception e)
                    {
                        e.printStackTrace();
                    }
                }
            }.start();


            while (true)
            {
            //将控制台输入的消息发送到服务器
                String msg =  mScanner.next();
                bw.write(msg);
                bw.newLine();
                bw.flush();

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new TCPClient().start();
    }
}

效果如下:
安卓中的Socket通信和Https通信中证书的校验方法_第5张图片
安卓中的Socket通信和Https通信中证书的校验方法_第6张图片
安卓中的Socket通信和Https通信中证书的校验方法_第7张图片
我们可以在对应的socket做一些标识,例如昵称什么的,然后就可以得到和真正的聊天类似的效果。

然后我们将这个功能迁移带客户端:
我们新建一个业务类,将客户端中带部分代码分割出去:

package com.example.chatroom.biz;

import android.os.Handler;
import android.os.Looper;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;

public class TCPClientBiz {
    private Socket socket ;
    private InputStream inputStream ;
    private OutputStream outputStream ;

    private Handler mUIHandler = new Handler(Looper.getMainLooper());


    private  OnMsgReceiveListener mListener;

    public void setOnMsgReceiveListener(OnMsgReceiveListener onMsgReceiveListener) {
        mListener = onMsgReceiveListener;
    }

    public TCPClientBiz() {

        new Thread() {
            @Override
            public void run() {
                try {
                    socket= new Socket("192.168.2.101",9090);
                    inputStream = socket.getInputStream();
                    outputStream = socket.getOutputStream();

                    readServerMsg();
                }
                catch (final Exception e)
                {
                    mUIHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            if (mListener !=null) {
                                mListener.onError(e);
                            }
                        }
                    });
                    e.printStackTrace();
                }
            }
        }.start();

    }

    public void sendMessage(final String msg ) {
        new Thread() {
            @Override
            public void run() {
                try {
                    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream));
                    bw.write(msg);
                    bw.newLine();
                    bw.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

    private void readServerMsg() throws IOException {
         BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
        String line = null;
        while ((line = br.readLine()) != null) {
            final String finalLine = line;
            mUIHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (mListener !=null) {
                        mListener.onMessageReceived(finalLine);
                    }
                }
            });

        }
    }

    public interface OnMsgReceiveListener
    {
        void onMessageReceived(String msg);
        void onError(Exception e);
    }

    public void onDestory()
    {

        try {
            if (socket!=null)
            {
                socket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            if (inputStream !=null)
            {
                inputStream.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            if (outputStream != null)
            {
                outputStream.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

然后是Activity的代码:

package com.example.client;


import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

import com.example.chatroom.biz.TCPClientBiz;

public class TCPActivity extends AppCompatActivity  {
    private EditText mEditText;
    private Button mButtonSend;
    private TextView mTextViewMessage;

    private TCPClientBiz tcpClientbiz;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_t_c_p);
        tcpClientbiz = new TCPClientBiz();
        tcpClientbiz.setOnMsgReceiveListener(new TCPClientBiz.OnMsgReceiveListener() {
            @Override
            public void onMessageReceived(String msg) {
                appendMessage2Content(msg);//将受到的消息放在textview中
            }

            @Override
            public void onError(Exception e) {

            }
        });

        initView();

        mButtonSend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mTextViewMessage.setText(" ");
                String messages = mEditText.getText().toString();
                if (TextUtils.isEmpty(messages))
                {
                    return;
                }
                appendMessage2Content("client:"+messages);
                tcpClientbiz.sendMessage(messages);

            }
        });
    }

    private void appendMessage2Content(String message) {
        mTextViewMessage.append(message+"\n");
    }

    private void initView() {
        mEditText = findViewById(R.id.input);
        mButtonSend = findViewById(R.id.send);
        mTextViewMessage = findViewById(R.id.message);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        tcpClientbiz.onDestory();
    }
}

安卓中的Socket通信和Https通信中证书的校验方法_第8张图片
这里需要注意的是,要将客户端的代码放在另外一个module 中,不然会运行不起来。

Part2-Https通信

Https是是一种采用了加密算法的通讯协议。为了安全起见,在安卓端访问使用了Https协议的服务的时候(服务并未获得CA证书)需要校验证书以及域名,来保证数据的安全性。

案例三:证书校验以及域名校验
我们先写一个Utils来访问一个链接:

package https;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;

public class HttpUtils {

    private static Handler mUIHandler = new Handler(Looper.getMainLooper());
    public interface HttpListener
    {
        void onSucceed(String content);
        void onFailed(Exception e);
    }

    public static void doGet(final Context context,final String urlStr, final HttpListener httpListener)
    {
        new Thread()
        {
            @Override
            public void run() {

                InputStream inputStream = null;
                try {
                    URL url = new URL(urlStr);
                    HttpsURLConnection httpConn = (HttpsURLConnection) url.openConnection();



                    //校验证书_方法1:
                    X509Certificate certificate = getCert(context);
                    TrustManager[] tm = {new MyX509TrustManager(certificate)};
                    SSLContext sslContext = SSLContext.getInstance("TLS");
                   

                    //校验证书_方法2:
                    String keyStoreType = KeyStore.getDefaultType();
                    KeyStore keyStore = KeyStore.getInstance(keyStoreType);
                    keyStore.load(null);
                    keyStore.setCertificateEntry("srca",certificate);

                    TrustManagerFactory trustManagerFactory
                            = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

                    trustManagerFactory.init(keyStore);

                    TrustManager[] tm1 = trustManagerFactory.getTrustManagers();


//在获取了TrustManager[]数组之后的步骤就相同了

                    sslContext.init(null,tm,new SecureRandom());
                    httpConn.setSSLSocketFactory(sslContext.getSocketFactory());

                    //校验域名
                    httpConn.setHostnameVerifier(new HostnameVerifier() {
                        @Override
                        public boolean verify(String hostname, SSLSession session) {

                            HostnameVerifier defaultHostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
                            return defaultHostnameVerifier.verify("12306.cn",session);



                        }
                    });


                    httpConn.setDoInput(true);
                    httpConn.setDoOutput(true);
                    httpConn.setRequestMethod("GET");
                    httpConn.setConnectTimeout(5*1000);
                    httpConn.setReadTimeout(5*1000);
                    httpConn.connect();

                    final StringBuilder content = new StringBuilder();
                    inputStream = httpConn.getInputStream();
                    byte[] buf  = new byte[2048];
                    int len = -1;
                    while ((len = inputStream.read(buf))!=-1)
                    {
                        content.append(new String(buf,0,len));
                    }
                    mUIHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            httpListener.onSucceed(content.toString());
                        }
                    });

                } catch (MalformedURLException e) {
                    e.printStackTrace();
                    httpListener.onFailed(e);
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (NoSuchAlgorithmException e) {
                    e.printStackTrace();
                } catch (KeyManagementException e) {
                    e.printStackTrace();
                } catch (KeyStoreException e) {
                    e.printStackTrace();
                } catch (CertificateException e) {
                    e.printStackTrace();
                } finally {
                    if (inputStream!=null)
                    {
                        try {
                            inputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }.start();

    }

    private static X509Certificate getCert(Context context) {

        try {
            InputStream inputStream = context.getAssets().open("xxx.cer");//在本地assets目录下保存的网站证书
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X509");
             return (X509Certificate) certificateFactory.generateCertificate(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (CertificateException e) {
            e.printStackTrace();
        }
        return null;
    }
}


其中,MyX509TrustManager类为:

package https;

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.X509TrustManager;

public class MyX509TrustManager implements X509TrustManager {

    private X509Certificate mySeverCert;

    public MyX509TrustManager(X509Certificate mySeverCert) {
        this.mySeverCert = mySeverCert;
    }

    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {

    }

    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        for (X509Certificate certificate : chain)
        {
            //证书是否过期以及合法性校验
            certificate.checkValidity();

            try {
                certificate.verify(mySeverCert.getPublicKey());
            } catch (Exception e) {
            //出现错误代表证书验证失败
               throw new CertificateException(e);
            }
        }

    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return new X509Certificate[0];
    }
}

证书校验的两种方法,第一种需要我们自己去校验,第二种是调用API为我们校验。

你可能感兴趣的:(Android路漫漫)