|  | 本文参考《Java网络编程核心技术详解》,作者:孙卫琴,电子工业出版社出版 源代码下载地址为:http://www.javathinker.net/kecheng/javanet/javanetsourcecode.rar
 
 以下EchoServer类创建了一个基于SSL的安全服务器,它处于服务器模式。
 
 | /* EchoServer.java*/ import java.net.*;
 import java.io.*;
 import javax.net.ssl.*;
 import java.security.*;
 public class EchoServer {
 private int port=8000;
 private SSLServerSocket serverSocket;
 
 public EchoServer() throws Exception {
 //输出跟踪日志
 //System.setProperty("javax.net.debug", "all");
 SSLContext context=createSSLContext();
 SSLServerSocketFactory factory=context.getServerSocketFactory();
 serverSocket =(SSLServerSocket)factory.createServerSocket(port);
 System.out.println("服务器启动");
 System.out.println(
 serverSocket.getUseClientMode()? "客户模式":"服务器模式");
 System.out.println(serverSocket.getNeedClientAuth()?
 "需要验证对方身份":"不需要验证对方身份");
 
 String[] supported=serverSocket.getSupportedCipherSuites();
 serverSocket.setEnabledCipherSuites(supported);
 }
 
 
 public SSLContext createSSLContext() throws Exception {
 //服务器用于证实自己身份的安全证书所在的密钥库
 String keyStoreFile = "test.keystore";
 String passphrase = "123456";
 KeyStore ks = KeyStore.getInstance("JKS");
 char[] password = passphrase.toCharArray();
 ks.load(new FileInputStream(keyStoreFile), password);
 KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
 kmf.init(ks, password);
 
 SSLContext sslContext = SSLContext.getInstance("SSL");
 sslContext.init(kmf.getKeyManagers(), null, null);
 
 //当要求客户端提供安全证书时,服务器端可创建TrustManagerFactory,
 //并由它创建TrustManager,TrustManger根据与之关联的KeyStore中的信息,
 //来决定是否相信客户提供的安全证书。
 
 //客户端用于证实自己身份的安全证书所在的密钥库
 //String trustStoreFile = "test.keystore";
 //KeyStore ts = KeyStore.getInstance("JKS");
 //ts.load(new FileInputStream(trustStoreFile), password);
 //TrustManagerFactory tmf =
 //    TrustManagerFactory.getInstance("SunX509");
 //tmf.init(ts);
 //sslContext.init(kmf.getKeyManagers(),
 //                 tmf.getTrustManagers(), null);
 
 return sslContext;
 }
 
 public String echo(String msg) {
 return "echo:" + msg;
 }
 
 private PrintWriter getWriter(Socket socket)throws IOException{
 OutputStream socketOut = socket.getOutputStream();
 return new PrintWriter(socketOut,true);
 }
 private BufferedReader getReader(Socket socket)throws IOException{
 InputStream socketIn = socket.getInputStream();
 return new BufferedReader(new InputStreamReader(socketIn));
 }
 
 public void service() {
 while (true) {
 Socket socket=null;
 try {
 socket = serverSocket.accept();  //等待客户连接
 System.out.println("New connection accepted "
 +socket.getInetAddress()
 + ":" +socket.getPort());
 BufferedReader br =getReader(socket);
 PrintWriter pw = getWriter(socket);
 
 String msg = null;
 while ((msg = br.readLine()) != null) {
 System.out.println(msg);
 pw.println(echo(msg));
 if (msg.equals("bye")) //如果客户发送的消息为“bye”,就结束通信
 break;
 }
 }catch (IOException e) {
 e.printStackTrace();
 }finally {
 try{
 if(socket!=null)socket.close();  //断开连接
 }catch (IOException e) {e.printStackTrace();}
 }
 }
 }
 
 public static void main(String args[])throws Exception {
 new EchoServer().service();
 }
 }
 | 
 以上EchoServer类先创建了SSLContext对象,然后由它创建SSLServerSocketFactory对象,再由该工厂对象创建SSLServerSocket对象。对于以下程序代码:
 
 
 
 | System.out.println(serverSocket.getUseClientMode()? "客户模式":"服务器模式");
 System.out.println(serverSocket.getNeedClientAuth()?
 "需要验证对方身份":"不需要需要验证对方身份");
 | 
 打印结果为:
 
 
 
 由此可见,默认情况下,SSLServerSocket处于服务器模式,必须向对方证实自身的身份,但不需要验证对方的身份,即不要求对方出示安全证书。
 
 如果希望程序运行时输出底层JSSE实现的日志信息,可以把“javax.net.debug”系统属性设为“all”:
 System.setProperty("javax.net.debug", "all");
 
 以下EchoClient类创建了一个基于SSL的安全客户,它处于客户模式。
 
 
 
 | /* EchoClient.java */ import java.net.*;
 import java.io.*;
 import javax.net.ssl.*;
 import java.security.*;
 public class EchoClient {
 private String host="localhost";
 private int port=8000;
 private SSLSocket socket;
 
 public EchoClient()throws IOException{
 SSLContext context=createSSLContext();
 SSLSocketFactory factory=context.getSocketFactory();
 socket=(SSLSocket)factory.createSocket(host,port);
 String[] supported=socket.getSupportedCipherSuites();
 socket.setEnabledCipherSuites(supported);
 System.out.println(socket.getUseClientMode()?
 "客户模式":"服务器模式");
 }
 
 public SSLContext createSSLContext() throws Exception {
 String passphrase = "123456";
 char[] password = passphrase.toCharArray();
 
 //设置客户端所信任的安全证书所在的密钥库
 String trustStoreFile = "test.keystore";
 KeyStore ts = KeyStore.getInstance("JKS");
 ts.load(new FileInputStream(trustStoreFile), password);
 TrustManagerFactory tmf =
 TrustManagerFactory.getInstance("SunX509");
 tmf.init(ts);
 
 SSLContext sslContext = SSLContext.getInstance("SSL");
 sslContext.init(null,tmf.getTrustManagers(), null);
 return sslContext;
 }
 public static void main(String args[])throws IOException{
 new EchoClient().talk();
 }
 private PrintWriter getWriter(Socket socket)throws IOException{
 OutputStream socketOut = socket.getOutputStream();
 return new PrintWriter(socketOut,true);
 }
 private BufferedReader getReader(Socket socket)throws IOException{
 InputStream socketIn = socket.getInputStream();
 return new BufferedReader(new InputStreamReader(socketIn));
 }
 public void talk()throws IOException {
 try{
 BufferedReader br=getReader(socket);
 PrintWriter pw=getWriter(socket);
 BufferedReader localReader=
 new BufferedReader(new InputStreamReader(System.in));
 String msg=null;
 while((msg=localReader.readLine())!=null){
 pw.println(msg);
 System.out.println(br.readLine());
 
 if(msg.equals("bye"))
 break;
 }
 }catch(IOException e){
 e.printStackTrace();
 }finally{
 try{socket.close();}catch(IOException e){e.printStackTrace();}
 }
 }
 }
 | 
 以上EchoClient类先创建了一个SSLSocketFactory对象,然后由它创建了SSLSocket对象。对于以下程序代码:
 
 
 
 | System.out.println(socket.getUseClientMode()? "客户模式":"服务器模式");
 | 
 打印结果为:
 
 
 
 由此可见,默认情况下,由SSLSocketFactory创建的SSLSocket对象处于客户模式,不必向对方证实自身的身份。
 EchoClient类依靠TrustManager来决定是否信任EchoServer出示的安全证书。EchoClient类的SSLSocketFactory对象是由SSLContext对象来创建的。这个SSLContext对象通过TrustManager来管理所信任的安全证书。在本例中,TrustManager所信任的安全证书位于test.keystore密钥库文件中。
 
 在本例中,服务器端向客户端出示的安全证书位于test.keystore密钥库文件中。在实际应用中,服务器端的密钥库文件中包含密钥对,从安全角度出发,客户端所信任的密钥库文件中应该仅仅包含公钥,所以服务器和客户端应该使用不同的密钥库文件。
 
 假定该文件与EchoServer.class以及EchoClient.class文件位于同一目录下。在DOS命令行中转到范例所在的chapter15目录下,按照以下步骤运行EchoServer和EchoClient:
 (1)设置classpath,运行命令“set classpath=C:\chapter15\classes”。
 (2)运行“start java EchoServer”命令,启动EchoServer服务器。
 (3)运行“ java  EchoClient”命令,启动EchoClient客户。
 
 
 
 程序猿的技术大观园:www.javathinker.net
 
 
 
 [这个贴子最后由 admin 在 2021-10-09 10:54:28 重新编辑]
 |  |