- 介绍
网络编程是Java中很重要的一块,实现的是应用层的网络协议。本文介绍如何使用socket开发,包括有TCP和UDP的代码实现。 关于UDP广播相关的内容,可以点击这里查看另外一篇文章。 普通的Socket是使用明文来传输的,那怎么才能加密这个传输通道呢?赶快下面的例子吧。
- TCP
下面的代码实现一个服务端监听,然后打印接收到的字符串数据,最后再给客户端返回一个字符串。 [codesyntax lang="java"]
1/** 2 * http://surenpi.com 3 */ 4package org.suren.test; 5 6import java.io.InputStream; 7import java.io.OutputStream; 8import java.net.ServerSocket; 9import java.net.Socket; 10import java.net.SocketAddress; 11 12/** 13 * @author suren 14 * @date 2015年9月2日 上午8:09:54 15 */ 16public class TcpServer 17{ 18 public static void main(String[] args) throws Exception 19 { 20 ServerSocket server = null; 21 22 try 23 { 24 server = new ServerSocket(8090); 25 26 while(true) 27 { 28 Socket client = server.accept(); 29 30 SocketAddress remoteAddr = client.getRemoteSocketAddress(); 31 InputStream input = client.getInputStream(); 32 OutputStream output = client.getOutputStream(); 33 34 System.out.println(remoteAddr); 35 36 byte[] buf = new byte[1024]; 37 int length = -1; 38 39 StringBuffer stringBuf = new StringBuffer(); 40 while((length = input.read(buf)) > 0) 41 { 42 stringBuf.append(new String(buf, 0, length)); 43 44 if(length < buf.length) 45 { 46 break; 47 } 48 } 49 50 System.out.println(stringBuf.toString()); 51 52 output.write("done".getBytes()); 53 54 System.out.println("server round over."); 55 56 client.close(); 57 } 58 } 59 finally 60 { 61 if(server != null) 62 { 63 server.close(); 64 65 System.out.println("server closed."); 66 } 67 } 68 } 69}
[/codesyntax] 下面是客户端的实现: [codesyntax lang="java"]
1/** 2 * http://surenpi.com 3 */ 4package org.suren.test; 5 6import java.io.IOException; 7import java.io.InputStream; 8import java.io.OutputStream; 9import java.net.InetSocketAddress; 10import java.net.Socket; 11import java.net.SocketAddress; 12 13/** 14 * @author suren 15 * @date 2015年9月2日 上午8:14:42 16 */ 17public class TcpClient 18{ 19 20 /** 21 * @param args 22 * @throws IOException 23 */ 24 public static void main(String[] args) throws IOException 25 { 26 Socket client = new Socket(); 27 28 SocketAddress addr = new InetSocketAddress("127.0.0.1", 8090); 29 30 client.connect(addr); 31 32 InputStream input = client.getInputStream(); 33 OutputStream output = client.getOutputStream(); 34 35 output.write("hello from client".getBytes()); 36 37 byte[] buf = new byte[1024]; 38 int length = -1; 39 40 System.out.println("client write over."); 41 42 StringBuffer stringBuf = new StringBuffer(); 43 while((length = input.read(buf)) > 0) 44 { 45 stringBuf.append(new String(buf, 0, length)); 46 47 if(length < buf.length) 48 { 49 break; 50 } 51 } 52 53 System.out.println(stringBuf.toString()); 54 55 client.close(); 56 } 57 58}
[/codesyntax]
- UDP
这里首先要提醒的是,UDP协议是不保证数据传输的完整性的,所以说如果对数据完整性要求很高的话,不建议采用这种协议。UDP相比TCP的优点是传输效率高,可以用在视频传输上。 [codesyntax lang="java"]
1/** 2 * http://surenpi.com 3 */ 4package org.suren.test; 5 6import java.io.IOException; 7import java.net.DatagramPacket; 8import java.net.DatagramSocket; 9 10/** 11 * @author suren 12 * @date 2015年9月2日 上午9:44:39 13 */ 14public class UdpServer 15{ 16 17 /** 18 * @param args 19 * @throws IOException 20 */ 21 public static void main(String[] args) throws IOException 22 { 23 try(DatagramSocket server = new DatagramSocket(9999)) 24 { 25 while(true) 26 { 27 int length = 1024; 28 byte[] buf = new byte[length]; 29 DatagramPacket packet = new DatagramPacket(buf, length); 30 31 server.receive(packet); 32 33 System.out.println("receive from client."); 34 35 buf = packet.getData(); 36 37 System.out.println(new String(buf, packet.getOffset(), packet.getLength())); 38 39 packet.setData("server replly".getBytes()); 40 server.send(packet); 41 } 42 } 43 } 44}
[/codesyntax] 以下是客户端代码(理论上udp是没有客户端和服务端之分的,从下面的代码就可以看出来,客户端和服务端没什么区别): [codesyntax lang="java"]
1/** 2 * http://surenpi.com 3 */ 4package org.suren.test; 5 6import java.io.IOException; 7import java.net.DatagramPacket; 8import java.net.DatagramSocket; 9import java.net.InetSocketAddress; 10 11/** 12 * @author suren 13 * @date 2015年9月2日 上午9:51:40 14 */ 15public class UdpClient 16{ 17 public static void main(String[] args) throws IOException 18 { 19 try(DatagramSocket client = new DatagramSocket()) 20 { 21 byte[] buf = "hello from udp client message.".getBytes(); 22 int length = buf.length; 23 DatagramPacket packet = new DatagramPacket(buf, length); 24 packet.setSocketAddress(new InetSocketAddress("localhost", 9999)); 25 26 client.send(packet); 27 28 client.receive(packet); 29 30 System.out.println(new String(packet.getData(), packet.getOffset(), packet.getLength())); 31 } 32 } 33}
[/codesyntax]
- 安全的TCP
上面介绍的TCP连接,发送的都是明文的数据,通过数据包拦截工具就可以完全看到发送和接收的内容。当然,我们可以通过把要发送的数据先做加密,然后再发送。这就需要自己来编写加密和解密的逻辑了,安全性完全在于你的加密算法。另外,我们还可以使用SSL的TCP连接来发送明文或者密文数据,这是一种可以和普通TCP连接无缝对接的方式——和上面的写法几乎完全一样,只是在获取Socket的方式上有所区别。 既然是一种安全的通讯方式,肯定少不了相应的机制了。我们这里需要 使用keytool工具来生成一个证书文件,下面的代码中会用到。 下面是服务端代码: [codesyntax lang="java"]
1/** 2 * http://surenpi.com 3 */ 4package org.suren.test; 5 6import java.io.File; 7import java.io.FileInputStream; 8import java.io.IOException; 9import java.io.InputStream; 10import java.io.OutputStream; 11import java.net.Socket; 12import java.security.KeyManagementException; 13import java.security.KeyStore; 14import java.security.KeyStoreException; 15import java.security.NoSuchAlgorithmException; 16import java.security.SecureRandom; 17import java.security.UnrecoverableKeyException; 18import java.security.cert.CertificateException; 19import java.security.cert.X509Certificate; 20 21import javax.net.ssl.KeyManagerFactory; 22import javax.net.ssl.SSLContext; 23import javax.net.ssl.SSLServerSocket; 24import javax.net.ssl.SSLServerSocketFactory; 25import javax.net.ssl.TrustManager; 26import javax.net.ssl.X509TrustManager; 27 28/** 29 * @author suren 30 * @date 2015年9月2日 上午10:11:54 31 */ 32public class SSLTcpServer 33{ 34 35 /** 36 * @param args 37 * @throws KeyStoreException 38 * @throws IOException 39 * @throws CertificateException 40 * @throws NoSuchAlgorithmException 41 * @throws UnrecoverableKeyException 42 * @throws KeyManagementException 43 */ 44 public static void main(String[] args) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, UnrecoverableKeyException, KeyManagementException 45 { 46 //证书加载 47 char[] pwd = "123456".toCharArray(); 48 KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); 49 50 try(InputStream input = new FileInputStream(new File("D:/suren"))) 51 { 52 keyStore.load(input, pwd); 53 } 54 55 KeyManagerFactory keyMgr = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); 56 keyMgr.init(keyStore, pwd); 57 58 //初始化ssl上下文 59 X509TrustManager x509m = new X509TrustManager(){ 60 61 @Override 62 public void checkClientTrusted(X509Certificate[] chain, 63 String authType) throws CertificateException 64 { 65 System.out.println("checkClientTrusted"); 66 } 67 68 @Override 69 public void checkServerTrusted(X509Certificate[] chain, 70 String authType) throws CertificateException 71 { 72 System.out.println("checkServerTrusted"); 73 } 74 75 @Override 76 public X509Certificate[] getAcceptedIssuers() 77 { 78 System.out.println("getAcceptedIssuers"); 79 return null; 80 } 81 }; 82 83 SSLContext sslContext = SSLContext.getInstance("SSL"); 84 sslContext.init(keyMgr.getKeyManagers(), 85 new TrustManager[]{x509m}, 86 new SecureRandom()); 87 88 SSLServerSocketFactory factory = sslContext.getServerSocketFactory(); 89 90 try(SSLServerSocket server = (SSLServerSocket) factory.createServerSocket(8900)) 91 { 92 System.out.println("ssl server socket created."); 93 94 while(true) 95 { 96 try(Socket client = server.accept()) 97 { 98 InputStream input = client.getInputStream(); 99 OutputStream output = client.getOutputStream(); 100 101 StringBuffer strBuf = new StringBuffer(); 102 103 int length = 1024; 104 byte[] buf = new byte[length]; 105 106 while((length = input.read(buf)) > 0) 107 { 108 strBuf.append(new String(buf, 0, length)); 109 110 if(length < buf.length) 111 { 112 break; 113 } 114 } 115 116 System.out.println(strBuf.toString()); 117 118 output.write("ssl server say done.".getBytes()); 119 } 120 } 121 } 122 } 123}
[/codesyntax] 下面是客户端代码: [codesyntax lang="java"]
1/** 2 * http://surenpi.com 3 */ 4package org.suren.test; 5 6import java.io.IOException; 7import java.io.InputStream; 8import java.io.OutputStream; 9import java.net.UnknownHostException; 10import java.security.KeyManagementException; 11import java.security.KeyStoreException; 12import java.security.NoSuchAlgorithmException; 13import java.security.SecureRandom; 14import java.security.UnrecoverableKeyException; 15import java.security.cert.CertificateException; 16import java.security.cert.X509Certificate; 17 18import javax.net.ssl.SSLContext; 19import javax.net.ssl.SSLSocket; 20import javax.net.ssl.SSLSocketFactory; 21import javax.net.ssl.TrustManager; 22import javax.net.ssl.X509TrustManager; 23 24/** 25 * @author suren 26 * @date 2015年9月2日 上午10:52:31 27 */ 28public class SSLTcpClient 29{ 30 31 /** 32 * @param args 33 * @throws IOException 34 * @throws UnknownHostException 35 * @throws NoSuchAlgorithmException 36 * @throws KeyManagementException 37 * @throws KeyStoreException 38 * @throws CertificateException 39 * @throws UnrecoverableKeyException 40 */ 41 public static void main(String[] args) throws UnknownHostException, IOException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, CertificateException, UnrecoverableKeyException 42 { 43 SSLContext context = SSLContext.getInstance("SSL"); 44 context.init(null, 45 new TrustManager[]{new X509TrustManager(){ 46 47 @Override 48 public void checkClientTrusted(X509Certificate[] chain, 49 String authType) throws CertificateException 50 { 51 } 52 53 @Override 54 public void checkServerTrusted(X509Certificate[] chain, 55 String authType) throws CertificateException 56 { 57 } 58 59 @Override 60 public X509Certificate[] getAcceptedIssuers() 61 { 62 return null; 63 } 64 }}, 65 new SecureRandom()); 66 67 SSLSocketFactory factory = context.getSocketFactory(); 68 69 try(SSLSocket client = (SSLSocket) factory.createSocket("localhost", 8900)) 70 { 71 InputStream input = client.getInputStream(); 72 OutputStream output = client.getOutputStream(); 73 74 output.write("from ssl client.".getBytes()); 75 76 StringBuffer strBuf = new StringBuffer(); 77 byte[] buf = new byte[1024]; 78 int len = -1; 79 while((len = input.read(buf)) > 0) 80 { 81 strBuf.append(new String(buf, 0, len)); 82 83 if(len < buf.length) 84 { 85 break; 86 } 87 } 88 89 System.out.println(strBuf); 90 } 91 } 92}
[/codesyntax]
- 参考
http://410063005.iteye.com/blog/1751243 http://www.ibm.com/developerworks/cn/java/j-lo-ssltls/