Java SSL Socket通訊示例

上一篇《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來處理通訊的問題,應該會比自己寫的性能好一些。

Java官方SSL Socket文檔

發佈了76 篇原創文章 · 獲贊 535 · 訪問量 95萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章