Java SSL Socket通訊示例
阿新 • • 發佈:2019-01-22
上一篇《OpenSSL與KeyStore指令小集》裡面說到,最近研究SSL加密,會給出一個Java的小示例。複製一份可以執行的程式碼到生產上是非常不負責任的行為,不過小示例可以帶我們入門,快速看清事物的本質。羅馬不是一天建成的。
本文將給出一個Java SSL Socket的小例子,包括了Server和Client。希望大家上手之後,要多去研究相關的資料,理解基礎概念。Java的優點是封裝得比較徹底,需要介入的地方比較少,缺點是隨著Java版本的升級和發展,會有很多新的概念和類湧出來,都要搞清楚要費不少力,另外程式碼量也比較大(生產級別的程式碼)。
具體程式碼
從最簡單來說,Java裡面只需要配置幾個系統屬性,建立及呼叫幾個SSL相關的物件即可。這四個屬性分別是:
- javax.net.ssl.keyStore
本方的密碼,證書等存放地點(KeyStore檔案地址)。 - javax.net.ssl.keyStorePassword
KeyStore的密碼。沒有密碼可以不填。 - javax.net.ssl.trustStore
受信任證書的存放地點(TrustKeyStore檔案地址)。 - javax.net.ssl.trustStorePassword
TrustKeyStore的密碼。沒有密碼可以不填。
KeyStore型別預設是JKS型別的,不是的話,還需要設定 javax.net.ssl.keyStoreType和javax.net.ssl.trustStoreType。
Server端程式碼
每一次收新的連線,都新開一個執行緒接待。生產上請用執行緒池等技術。更推薦用Netty或Mina等框架處理。
public class SslServer { public static void main(String[] args) throws Exception { System.setProperty("javax.net.debug", "ssl,handshake"); System.setProperty("javax.net.ssl.keyStore", "./cfg/server.jks"); System.setProperty("javax.net.ssl.keyStorePassword", "123456"); System.setProperty("javax.net.ssl.trustStore", "./cfg/clienttrust.jks"); System.setProperty("javax.net.ssl.trustStorePassword", "123456"); SSLServerSocketFactory serverSocketFactory = (SSLServerSocketFactory) SSLServerSocketFactory .getDefault(); SSLServerSocket serverSocket = (SSLServerSocket) serverSocketFactory .createServerSocket(9100); // 要求客戶端身份驗證 serverSocket.setNeedClientAuth(true); while (true) { SSLSocket socket = (SSLSocket) serverSocket.accept(); Accepter accepter = new Accepter(socket); accepter.service(); } } static class Accepter implements Runnable { private SSLSocket socket; public Accepter(SSLSocket socket) { this.socket = socket; } public void service() { Thread thread = new Thread(this); thread.start(); } @Override public void run() { try { InputStream inputStream = socket.getInputStream(); InputStreamReader inputstreamreader = new InputStreamReader( inputStream); BufferedReader bufferedreader = new BufferedReader( inputstreamreader); String string = null; while ((string = bufferedreader.readLine()) != null) { System.out.println(string); System.out.flush(); } } catch (Exception e) { // replace with other code e.printStackTrace(); } } } }
Client程式碼
建立連線,併發一個訊息給Server。很簡單。記得換行符以及呼叫flush方法。
public class SslClient {
public static void main(String[] args) throws Exception {
System.setProperty("javax.net.debug", "ssl,handshake");
System.setProperty("javax.net.ssl.keyStore", "./cfg/client.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "123456");
System.setProperty("javax.net.ssl.trustStore", "./cfg/servertrust.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "123456");
SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory
.getDefault();
SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket(
"127.0.0.1", 9100);
OutputStream outputStream = sslsocket.getOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(
new OutputStreamWriter(outputStream));
bufferedWriter.write("沉睡的雄獅\n");
bufferedWriter.flush();
TimeUnit.SECONDS.sleep(2000);
}
}
結束語
JDK後來加了SSLEngine這個類,具有非同步通訊的能力。不過看官方文件,給出的程式碼很長。還是那句話,有條件的推薦用Netty或者Mina來處理通訊的問題,應該會比自己寫的效能好一些。