1. 程式人生 > >java語言搭建SSL的Socket併發送字串訊息(最簡單應用例項/常見異常及解決)

java語言搭建SSL的Socket併發送字串訊息(最簡單應用例項/常見異常及解決)

我看了幾篇微博,有的非常詳實,作為深入學習資料非常好。

但是有的說是例項吧...無關測試程式碼太多,感覺就是畫蛇添足。各種祕鑰庫管理感覺都是非必要的。

索性自己寫一個。順便記錄一些常見的異常,如:

Cannot recover key
certificate_unknown
signature check failed
java.net.SocketException: Connection reset
Received fatal alert: handshake_failure

---------------------

>基礎知識(有興趣深入瞭解機制可見此)

簡單看一下有關SSL的類的關係:

通訊過程、加密原理和深入學習看此:

---------------------

>開始例項

首先,你要知道普通的Socket是怎麼建立的,如果你不瞭解這一項,見此:

1.客戶端的搭建

與常見的Socket搭建沒有什麼差別,唯一不同的是——sslsocket是從工廠類中獲取的,如下:

//1.獲取SSLSocketFactory物件
SocketFactory factory = SSLSocketFactory.getDefault();
//2.從工廠類中獲取sslsocket並提供伺服器ip和埠引數
Socket sslsocket = factory.createSocket("127.0.0.1", 9100);
//3.獲取輸出流,幷包裝成UTF-8編碼的快取位元組流(注意包裝成UTF8,否則會中文亂碼)
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(sslsocket.getOutputStream(),"UTF-8")); 
//4.開始輸出文字等
out.write("This is message:你好"+"\n");//這裡一定要加一個換行符,理由見下文
out.flush();


2.伺服器的搭建

//1.獲取工廠類
ServerSocketFactory factory =  SSLServerSocketFactory.getDefault();
//2.從工廠類中獲取相應的sslserversocket
SSLServerSocket serverSocket=(SSLServerSocket) factory.createServerSocket(9100); 
//3.要求客戶端進行ssl認證
serverSocket.setNeedClientAuth(true); 
//4.等待客戶端連線
Socket socket =serverSocket.accept();
//5.獲取輸入流,幷包裝成...
BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream(),"UTF-8"));
//6.輸出客戶端發來的資訊
System.out.println("Server Log:"+in.readLine())

3.祕鑰的建立及SSL環境的搭建

在windows環境一下,按win+R開啟cmd控制檯。
進入你java JDK的碟符,如輸入[ d: ]以進入d盤
輸入[cd+路徑],進入jdk目錄下的bin資料夾,注意轉義字元\\和/的使用,如:

cd jdk1.8/bin


接下來,我們要為客戶端和伺服器利用該目錄下的keytool工具生成祕鑰庫,用以ssl認證時進行握手動作。

在cmd中如輸入以下六行命令:

//1.建立伺服器祕鑰庫server_ks.jks,此處我給的密碼為server(注意這裡-storepass server和-keypass server要一致,否則會報出異常Cannot recover key)
keytool -genkey -keystore ./server_ks.jks -storepass server -keyalg RSA -keypass server
//2.建立客戶端祕鑰庫client_ks.jks,此處我給的密碼為client(密碼一致性同上)
keytool -genkey -keystore ./client_ks.jks -storepass client -keyalg RSA -keypass client
//3.把伺服器祕鑰庫server_ks.jks裡的證書匯出為server.cer
keytool -export -keystore ./server_ks.jks -storepass server -file ./server.cer
//4.把客戶端祕鑰庫client_ks.jks裡的證書匯出為client.cer
keytool -export -keystore ./client_ks.jks -storepass client -file ./client.cer
//5.把server.cer匯入伺服器信任祕鑰庫clientTrust_ks.jks,放於客戶端告訴客戶端哪些伺服器是可以信任的
keytool -import -keystore ./serverTrust_ks.jks -storepass client -file ./server.cer
//6.把client.cer匯入客戶端信任祕鑰庫serverTrust_ks.jks,...
keytool -import -keystore ./clientTrust_ks.jks -storepass server -file ./client.cer

邏輯圖如下:

4.為客戶端設定祕鑰庫和信任祕鑰庫:

System.setProperty("javax.net.ssl.keyStore", keystorePath);  
System.setProperty("javax.net.ssl.keyStorePassword", keystorePassword);  
System.setProperty("javax.net.ssl.trustStore", trustKeystorePath);  
System.setProperty("javax.net.ssl.trustStorePassword",keystorePassword);

其中,如果沒有密碼,就不用填寫相應的字串。建議結合完整例項程式碼來理解上面四個步驟:

-------------------------------

>完整例項程式碼

1.客戶端

public class ClientSSLTest {
	
    static String keystorePath = "你的路徑/client_ks.jks";
    static String trustKeystorePath = "你的路徑/serverTrust_ks.jks";
    static String keystorePassword = "client";
    public static void main(String args[]) throws Exception{
	//System.setProperty("javax.net.debug", "ssl,handshake");  
        System.setProperty("javax.net.ssl.keyStore", keystorePath);  
        System.setProperty("javax.net.ssl.keyStorePassword", keystorePassword);  
        System.setProperty("javax.net.ssl.trustStore", trustKeystorePath);  
        System.setProperty("javax.net.ssl.trustStorePassword",keystorePassword);  
        
	SocketFactory factory = SSLSocketFactory.getDefault();  
	Socket sslsocket = factory.createSocket("127.0.0.1", 9100);  
	System.out.println("Client Connected");
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(sslsocket.getOutputStream(),"UTF-8"));  
        
        out.write("This is message:你好"+"\n");
        out.flush();
        System.out.println("Msg Sent");
        sslsocket.close();
    }
}


2.伺服器

public class ServerSSLTest {
    static String keystorePath = "你的路徑/server_ks.jks";
    static String trustKeystorePath = "你的路徑/clientTrust_ks.jks";
    static String keystorePassword = "server";
    public static void main(String args[]) throws Exception{
	//System.setProperty("javax.net.debug", "ssl,handshake");  
        System.setProperty("javax.net.ssl.keyStore", keystorePath);  
        System.setProperty("javax.net.ssl.keyStorePassword", keystorePassword);  
        System.setProperty("javax.net.ssl.trustStore", trustKeystorePath);  
        System.setProperty("javax.net.ssl.trustStorePassword",keystorePassword);  
		
	ServerSocketFactory factory =  SSLServerSocketFactory.getDefault();
	SSLServerSocket serverSocket=(SSLServerSocket) factory.createServerSocket(9100); 
	serverSocket.setNeedClientAuth(true); 
	System.out.println("Server Open");
	Socket socket =serverSocket.accept();
	BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream(),"UTF-8"));
	System.out.println("Server Log:"+in.readLine());
    }
}

伺服器輸出:

>常見異常

1.Cannot recover key

原因及解決方法:

建立祕鑰庫時祕鑰庫主密碼和第二密碼不同,詳見用keytool建立祕鑰庫時6行命令裡的第一二行

2.certificate_unknown

原因及解決方法:

伺服器或客戶端未持有相應的證書,一般是由於信任祕鑰庫和祕鑰庫證書匯入及存放時的邏輯混亂造成的,建議參考邏輯圖輸命令。

3.no cipher suites in common

原因及解決方法:

沒有匯入證書,請重新確認上方keytool的使用是否正確,並結合完整例項程式碼進行邏輯確認。通知別忘了檢查密碼是否正確、祕鑰庫的路徑是否正確。

4.Received fatal alert: handshake_failure

在嘗試過很多方法,但依舊錯誤的話...

原因及解決方法:

有可能是因為JDK版本的原因,你需要下載官方替換包:

替換jdk\jre\lib\security下的那兩個檔案。

5.signature check failed

解決方法:嘗試把匯出的兩個證書(.cer)拷貝放到jdk\jre\lib\security檔案下

6.Connection reset

socket中的流已斷開,建議嘗試flush或檢查是否有免檢異常、close方法。

相關推薦

java語言搭建SSL的Socket併發字串訊息(簡單應用例項/常見異常解決)

我看了幾篇微博,有的非常詳實,作為深入學習資料非常好。 但是有的說是例項吧...無關測試程式碼太多,感覺就是畫蛇添足。各種祕鑰庫管理感覺都是非必要的。 索性自己寫一個。順便記錄一些常見的異常,如: Cannot recover key certificate_unkno

java web 常見異常解決辦法

eset log const 鍵值 cannot tomcat action asp tex javax.servlet.ServletException: javax/servlet/jsp/SkipPageException 重啟tomcat, javax.serv

jenkins在遠端主機執行指令碼併發郵件訊息

1、先安裝好相應的SSH等外掛 2、配置好在遠端主機上面的憑據,如圖所示:   3、配置郵件傳送的伺服器及使用者等,為圖省事,本次實驗當中配置的傳送伺服器是localhost     4、新增遠端主機,並配好剛才新增的憑據

JAVA語言基礎——(五)字串(逆置)

一、String下的方法 package practise; import java.util.Arrays; import java.util.Scanner; public class StringMethod { public static String leftTurn(S

java語言搭建app後臺入門

最近由於後臺開發人員有其他任務,導致app後臺開發人手不夠,因此公司讓我自己學習寫伺服器介面。在學習java基礎後,發現不知道下一步該學習什麼知識點,javaweb裡的知識點,相關框架太多。在遇到專案比較緊急的時候,時間不允許我們按部就班學習所有的知識點,因此這

使用gitlab ci構建IOS包併發通知訊息到企業微信

在之前的文章中,我們介紹了使用gitlab ci構建Android包的方法。今天我們介紹使用gitlab ci如何構建IOS包,並且在打包成功或者失敗時,如何將訊息通知到企業微信。 如果對gitlab ci還不熟悉的,可以參考之前的文章[使用gitlab ci構建Android包](https://mp.w

Java練習】獲取兩個字串長的相同欄位

獲取兩個字串中最長的子串並輸出。 思路解析: 1.首先考慮我們要知道長度最短的字串,這樣子在比較的次數會更少。 2.我們首先從長度最小的字串每次擷取一小段判斷是否在大串中 3.考慮到有可能有多個長度相同的子串,那麼我們就應該將他們同時儲存到集合中 4.要多考慮到各種異常的發生。

Java面試題演算法篇尋找字串長的重複元素子串

package com.puhui.goosecard.web.utils; // Java program to find the maximum consecutive // repeating character in given string class GFG

java String類-獲取兩個字串長相同子串

/* 獲取兩個字串中最大相同子串。枚舉出長度較短的字串的所有子串。將子串放在字串陣列中。 通過迴圈判斷長度較長的字串中是否包含字串陣列中的元素,並返回包含且最長的子字串。 */ class Stri

Java併發程式設計之CAS第三篇-CAS的缺點解決辦法

Java併發程式設計之CAS第三篇-CAS的缺點 通過前兩篇的文章介紹,我們知道了CAS是什麼以及檢視原始碼瞭解CAS原理。那麼在多執行緒併發環境中,的缺點是什麼呢?這篇文章我們就來討論討論 本篇是《凱哥(凱哥Java:kagejava)併發程式設計學習》系列之《CAS系列》教程的第三篇:CAS的缺點有哪些?

使用java實現快速排序(我認為是簡單容易理解的版本)

一切都在程式碼和註釋之中。複製貼上就能跑,邊跑邊看才是最愉快的。 所以,話不多說,放碼過來。   public class QuickSort { public static void main(String[] args) { int x[]={6,1,2,7,9,1

java中在使用類時的一些常見錯誤解決方法

關於java中類的一些常見錯誤及解決方法 1.定義了一個主類,如 public class TestCircle{//此時這裡會顯示“class TestCircle”has never been used“ public void main(String[] args){…}; class

併發快取處理之——快取穿透的幾種形式解決方案

快取失效的幾種形式 1 快取穿透 快取穿透是指查詢一個一定不存在的資料,由於快取是不命中時被動寫的,並且出於容錯考慮,如果從儲存層查不到資料則不寫入快取,這將導致這個不存在的資料每次請求都要到儲存層去查詢,失去了快取的意義。在流量大時,可能DB就掛掉了,要是有人利用不存在

從零開始的c語言連結串列學習 001--建立一個簡單基礎的連結串列

因為各種原因,儘管c語言期末考也拿了八十多分,卻仍然對連結串列處在完全甍逼的狀態,以至於之後的資料結構課聽天書,實驗課做不出來,於是決定重學一波連結串列的知識,特此記錄筆記 001—建立一個簡單的連結串列 1.1 認識連結串列 所謂連結串列,一言蔽之就是一連串帶

開發環境搭建-CentOS7安裝MySql5.7-Yum簡單的安裝方法

一、前言 yum是linux安裝軟體的利器,一個命令直接下載編譯安裝一條龍服務,簡單方便,但CentOS7的yum源中預設是沒有mysql,所以我們要先下載yum源。 二、實踐 1.檢視是否有mysql 如果有就解除安裝以前的mysql-百度一下linux完全解除安裝my

Java計算兩個經緯度間的距離簡單的方式

開發中經常會遇到計算兩個點(經緯度)之間的距離或者計算最近門店的場景,下面簡單實現一下如何計算兩個經緯度之間相隔的距離。 1、匯入geodesy的maven依賴 或者到阿里雲maven倉庫下載jar包 <dependency>   <groupId>org.gavaghan&

java中MongoDB的簡單應用例項

1 首先載入 MongoDB的jar包。下載Jar包連結 2然後進行相應的配置。如我當前專案是在web-pom.xml 的的節點下配置。 <dependency> <groupId>org.mo

Java常見異常解決辦法

1、java.lang.ArithmeticException 算術運算異常,因為除數為0,所以引發了算數異常 2、Java.lang.StringIndexOutOfBoundsException: String index out of range: -1 這

java獲取properties配置檔案中某個屬性簡單方法

    假如我想獲取src目錄下sysConfig.properties中的uploadpath屬性的值 方法如下所示: private static final ResourceBundle bundle = java.util.ResourceBundle.getBundle(

Java常見的記憶體溢位異常解決方法

Java的記憶體溢位,主要是兩方面的異常:堆記憶體溢位、非堆記憶體溢位。 一、 java.lang.OutOfMemoryError: Java heap space。 Heap size 設定 JVM堆的設定是指java程式執行過程中JVM可以調配使用的記憶體空間的設定