- 介绍
网络编程是Java中很重要的一块,实现的是应用层的网络协议。本文介绍如何使用socket开发,包括有TCP和UDP的代码实现。 关于UDP广播相关的内容,可以点击这里查看另外一篇文章。 普通的Socket是使用明文来传输的,那怎么才能加密这个传输通道呢?赶快下面的例子吧。
- TCP
下面的代码实现一个服务端监听,然后打印接收到的字符串数据,最后再给客户端返回一个字符串。 [codesyntax lang="java"]
/**
* http://surenpi.com
*/
package org.suren.test;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
/**
* @author suren
* @date 2015年9月2日 上午8:09:54
*/
public class TcpServer
{
public static void main(String[] args) throws Exception
{
ServerSocket server = null;
try
{
server = new ServerSocket(8090);
while(true)
{
Socket client = server.accept();
SocketAddress remoteAddr = client.getRemoteSocketAddress();
InputStream input = client.getInputStream();
OutputStream output = client.getOutputStream();
System.out.println(remoteAddr);
byte[] buf = new byte[1024];
int length = -1;
StringBuffer stringBuf = new StringBuffer();
while((length = input.read(buf)) > 0)
{
stringBuf.append(new String(buf, 0, length));
if(length < buf.length)
{
break;
}
}
System.out.println(stringBuf.toString());
output.write("done".getBytes());
System.out.println("server round over.");
client.close();
}
}
finally
{
if(server != null)
{
server.close();
System.out.println("server closed.");
}
}
}
}
[/codesyntax] 下面是客户端的实现: [codesyntax lang="java"]
/**
* http://surenpi.com
*/
package org.suren.test;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
/**
* @author suren
* @date 2015年9月2日 上午8:14:42
*/
public class TcpClient
{
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException
{
Socket client = new Socket();
SocketAddress addr = new InetSocketAddress("127.0.0.1", 8090);
client.connect(addr);
InputStream input = client.getInputStream();
OutputStream output = client.getOutputStream();
output.write("hello from client".getBytes());
byte[] buf = new byte[1024];
int length = -1;
System.out.println("client write over.");
StringBuffer stringBuf = new StringBuffer();
while((length = input.read(buf)) > 0)
{
stringBuf.append(new String(buf, 0, length));
if(length < buf.length)
{
break;
}
}
System.out.println(stringBuf.toString());
client.close();
}
}
[/codesyntax]
- UDP
这里首先要提醒的是,UDP协议是不保证数据传输的完整性的,所以说如果对数据完整性要求很高的话,不建议采用这种协议。UDP相比TCP的优点是传输效率高,可以用在视频传输上。 [codesyntax lang="java"]
/**
* http://surenpi.com
*/
package org.suren.test;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
/**
* @author suren
* @date 2015年9月2日 上午9:44:39
*/
public class UdpServer
{
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException
{
try(DatagramSocket server = new DatagramSocket(9999))
{
while(true)
{
int length = 1024;
byte[] buf = new byte[length];
DatagramPacket packet = new DatagramPacket(buf, length);
server.receive(packet);
System.out.println("receive from client.");
buf = packet.getData();
System.out.println(new String(buf, packet.getOffset(), packet.getLength()));
packet.setData("server replly".getBytes());
server.send(packet);
}
}
}
}
[/codesyntax] 以下是客户端代码(理论上udp是没有客户端和服务端之分的,从下面的代码就可以看出来,客户端和服务端没什么区别): [codesyntax lang="java"]
/**
* http://surenpi.com
*/
package org.suren.test;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
/**
* @author suren
* @date 2015年9月2日 上午9:51:40
*/
public class UdpClient
{
public static void main(String[] args) throws IOException
{
try(DatagramSocket client = new DatagramSocket())
{
byte[] buf = "hello from udp client message.".getBytes();
int length = buf.length;
DatagramPacket packet = new DatagramPacket(buf, length);
packet.setSocketAddress(new InetSocketAddress("localhost", 9999));
client.send(packet);
client.receive(packet);
System.out.println(new String(packet.getData(), packet.getOffset(), packet.getLength()));
}
}
}
[/codesyntax]
- 安全的TCP
上面介绍的TCP连接,发送的都是明文的数据,通过数据包拦截工具就可以完全看到发送和接收的内容。当然,我们可以通过把要发送的数据先做加密,然后再发送。这就需要自己来编写加密和解密的逻辑了,安全性完全在于你的加密算法。另外,我们还可以使用SSL的TCP连接来发送明文或者密文数据,这是一种可以和普通TCP连接无缝对接的方式——和上面的写法几乎完全一样,只是在获取Socket的方式上有所区别。 既然是一种安全的通讯方式,肯定少不了相应的机制了。我们这里需要 使用keytool工具来生成一个证书文件,下面的代码中会用到。 下面是服务端代码: [codesyntax lang="java"]
/**
* http://surenpi.com
*/
package org.suren.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
/**
* @author suren
* @date 2015年9月2日 上午10:11:54
*/
public class SSLTcpServer
{
/**
* @param args
* @throws KeyStoreException
* @throws IOException
* @throws CertificateException
* @throws NoSuchAlgorithmException
* @throws UnrecoverableKeyException
* @throws KeyManagementException
*/
public static void main(String[] args) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, UnrecoverableKeyException, KeyManagementException
{
//证书加载
char[] pwd = "123456".toCharArray();
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
try(InputStream input = new FileInputStream(new File("D:/suren")))
{
keyStore.load(input, pwd);
}
KeyManagerFactory keyMgr = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyMgr.init(keyStore, pwd);
//初始化ssl上下文
X509TrustManager x509m = new X509TrustManager(){
@Override
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException
{
System.out.println("checkClientTrusted");
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException
{
System.out.println("checkServerTrusted");
}
@Override
public X509Certificate[] getAcceptedIssuers()
{
System.out.println("getAcceptedIssuers");
return null;
}
};
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(keyMgr.getKeyManagers(),
new TrustManager[]{x509m},
new SecureRandom());
SSLServerSocketFactory factory = sslContext.getServerSocketFactory();
try(SSLServerSocket server = (SSLServerSocket) factory.createServerSocket(8900))
{
System.out.println("ssl server socket created.");
while(true)
{
try(Socket client = server.accept())
{
InputStream input = client.getInputStream();
OutputStream output = client.getOutputStream();
StringBuffer strBuf = new StringBuffer();
int length = 1024;
byte[] buf = new byte[length];
while((length = input.read(buf)) > 0)
{
strBuf.append(new String(buf, 0, length));
if(length < buf.length)
{
break;
}
}
System.out.println(strBuf.toString());
output.write("ssl server say done.".getBytes());
}
}
}
}
}
[/codesyntax] 下面是客户端代码: [codesyntax lang="java"]
/**
* http://surenpi.com
*/
package org.suren.test;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
/**
* @author suren
* @date 2015年9月2日 上午10:52:31
*/
public class SSLTcpClient
{
/**
* @param args
* @throws IOException
* @throws UnknownHostException
* @throws NoSuchAlgorithmException
* @throws KeyManagementException
* @throws KeyStoreException
* @throws CertificateException
* @throws UnrecoverableKeyException
*/
public static void main(String[] args) throws UnknownHostException, IOException, NoSuchAlgorithmException, KeyManagementException, KeyStoreException, CertificateException, UnrecoverableKeyException
{
SSLContext context = SSLContext.getInstance("SSL");
context.init(null,
new TrustManager[]{new X509TrustManager(){
@Override
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException
{
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException
{
}
@Override
public X509Certificate[] getAcceptedIssuers()
{
return null;
}
}},
new SecureRandom());
SSLSocketFactory factory = context.getSocketFactory();
try(SSLSocket client = (SSLSocket) factory.createSocket("localhost", 8900))
{
InputStream input = client.getInputStream();
OutputStream output = client.getOutputStream();
output.write("from ssl client.".getBytes());
StringBuffer strBuf = new StringBuffer();
byte[] buf = new byte[1024];
int len = -1;
while((len = input.read(buf)) > 0)
{
strBuf.append(new String(buf, 0, len));
if(len < buf.length)
{
break;
}
}
System.out.println(strBuf);
}
}
}
[/codesyntax]
- 参考
http://410063005.iteye.com/blog/1751243 http://www.ibm.com/developerworks/cn/java/j-lo-ssltls/