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();
}
}
}
}
測試結果如下:
值得注意的是, 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>
就是這個樣子的:
遷移之後,安卓端代碼如下:
首先我們將消息發送的業務邏輯遷移到一個新的類中,代碼和之前客戶端的基本一致:
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);
}
}
結果如下:
案例二: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做一些標識,例如暱稱什麼的,然後就可以得到和真正的聊天類似的效果。
然後我們將這個功能遷移帶客戶端:
我們新建一個業務類,將客戶端中帶部分代碼分割出去:
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();
}
}
這裏需要注意的是,要將客戶端的代碼放在另外一個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爲我們校驗。