本次使用nio实现socket客户端和服务端的通信,并且在服务端为每一个新建的连接创建一个线程负责维持和客户端的通信。
使用nio实现的阻塞的socket与普通方式实现的通信相比较仅仅是实现方式不同,其实质的运行原理是一样的。在此仅仅作为一个nio的入门示例。
nio来做socket主要用到两个类ServerSocketChannel(服务器socket)和SocketChannel(客户端socket)。
Channel的简单介绍:ServerSocketChannel和SocketChannel。Java NIO的通道类似流,但又有些不同:
1. 既可以从通道中读取数据,又可以写数据到通道。但流的读写通常是单向的。
2. 通道可以异步地读写。
3. 通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入。
Server端程序:
package com.henushang.socket.chapter4nio;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.henushang.socket.util.SocketUtils;
public class EchoServer {
private int port = 8000;
private ServerSocketChannel serverSocketChannel;
private ExecutorService executorService;
private final int POOL_SIZE = 4;
public EchoServer() throws Exception {
executorService = Executors.newFixedThreadPool(Runtime.getRuntime()
.availableProcessors() * POOL_SIZE);
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(port));
System.out.println("等待连接...");
}
public void service() {
SocketChannel socketChannel = null;
while (true) {
try {
System.out.println("waitting for connect...");
socketChannel = serverSocketChannel.accept();
System.out.println("get the connect...");
Thread.sleep(500);
executorService.execute(new Handler(socketChannel));
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws Exception {
new EchoServer().service();
}
class Handler implements Runnable {
private SocketChannel socketChannel = null;
public Handler(SocketChannel socketChannel) {
this.socketChannel = socketChannel;
}
@Override
public void run() {
handler(socketChannel);
}
private void handler(SocketChannel socketChannel) {
System.out.println("new connection accepted:"
+ socketChannel.socket().getInetAddress() + ":"
+ socketChannel.socket().getPort());
try {
BufferedReader reader = SocketUtils
.getReader(this.socketChannel);
PrintWriter pw = SocketUtils.getWriter(this.socketChannel);
String msg = null;
while (true) {
if ((msg = reader.readLine()) != null) {
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(msg);
// pw.write(SocketUtils.echo(msg)+"\r\n");
pw.println(SocketUtils.echo(msg));
pw.flush();
if ("bye".equals(msg)) {
break;
}
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
SocketUtils.close(socketChannel);
}
}
}
}
Client端程序:
package com.henushang.socket.chapter4nio;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.channels.SocketChannel;
import com.henushang.socket.util.SocketUtils;
public class EchoClient {
private SocketChannel socketChannel;
private int port = 8000;
public EchoClient() throws Exception {
socketChannel = SocketChannel.open();
InetAddress inetAddress = InetAddress.getLocalHost();
InetSocketAddress inetSocketAddress = new InetSocketAddress(inetAddress, port);
socketChannel.connect(inetSocketAddress);
System.out.println("准备连接服务器");
}
public static void main(String[] args) throws Exception {
new EchoClient().talk();
}
public void talk() {
try {
BufferedReader reader = SocketUtils.getReader(socketChannel.socket());
PrintWriter pw = SocketUtils.getWriter(socketChannel.socket());
BufferedReader localreaderReader = new BufferedReader(new InputStreamReader(System.in));
String msg = null;
while ((msg = localreaderReader.readLine()) != null) {
System.out.println(msg);
pw.println(msg);
pw.flush();
System.out.println(reader.readLine());
if ("bye".equals(msg)) {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}finally{
SocketUtils.close(socketChannel);
}
}
}
SocketUtils:(与以前的一样)
package com.henushang.socket.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.nio.channels.SocketChannel;
public class SocketUtils {
public static PrintWriter getWriter(Socket socket) throws IOException {
OutputStream os = socket.getOutputStream();
return new PrintWriter(os);
}
public static PrintWriter getWriter(SocketChannel socketChannel) throws IOException {
return getWriter(socketChannel.socket());
}
public static BufferedReader getReader(Socket socket) throws IOException{
InputStream is = socket.getInputStream();
return new BufferedReader(new InputStreamReader(is, "UTF-8"));
}
public static BufferedReader getReader(SocketChannel socketChannel) throws IOException{
return getReader(socketChannel.socket());
}
public static void close(Socket socket) {
try {
if (socket != null) {
socket.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void close(SocketChannel socketChannel) {
try {
if (socketChannel != null) {
socketChannel.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static String echo(String msg) {
return "echo:" + msg;
}
}