在原有基础上考虑了编码与解码的问题,还有消息发送的两个重要方法调用疏忽
public abstract int write(ByteBuffer src) 将字节序列从给定的缓冲区中写入此通道。
public abstract int read(ByteBuffer dst) 将字节序列从此通道中读入给定的缓冲区。
下面代码在关闭连接时还有问题,服务器可以与客户端断开,但是客户端断开后没有退出,再次操作会出现异常。
服务器端代码实现:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Calendar;
import java.util.Iterator;
public class TestServer {
public static void main(String[] args) {
new Thread(new EchoServer(1982)).start();
}
}
class EchoServer implements Runnable {
//要监听的端口号
private int port;
//生成一个信号监视器
private Selector s;
//读缓冲区
private ByteBuffer r_bBuf = ByteBuffer.allocate(1024);
private ByteBuffer w_bBuf;
public EchoServer(int port) {
this.port = port;
try {
s = Selector.open();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
try {
//生成一个ServerScoket通道的实例对象,用于侦听可能发生的IO事件
ServerSocketChannel ssc = ServerSocketChannel.open();
//将该通道设置为异步方式
ssc.configureBlocking(false);
//绑定到一个指定的端口
ssc.socket().bind(new InetSocketAddress(port));
//注册特定类型的事件到信号监视器上
ssc.register(s, SelectionKey.OP_ACCEPT);
System.out.println("The server has been launched...");
while(true) {
//将会阻塞执行,直到有事件发生
s.select();
Iterator<SelectionKey> it = s.selectedKeys().iterator();
while(it.hasNext()) {
SelectionKey key = it.next();
//key定义了四种不同形式的操作
switch(key.readyOps()) {
case SelectionKey.OP_ACCEPT :
dealwithAccept(key);
break;
case SelectionKey.OP_CONNECT :
break;
case SelectionKey.OP_READ :
dealwithRead(key);
break;
case SelectionKey.OP_WRITE :
break;
}
//处理结束后移除当前事件,以免重复处理
it.remove();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
//处理接收连接的事件
private void dealwithAccept(SelectionKey key) {
try {
System.out.println("新的客户端请求连接...");
ServerSocketChannel server = (ServerSocketChannel)key.channel();
SocketChannel sc = server.accept();
sc.configureBlocking(false);
//注册读事件
sc.register(s, SelectionKey.OP_READ);
System.out.println("客户端连接成功...");
} catch (IOException e) {
e.printStackTrace();
}
}
//处理客户端发来的消息,处理读事件
private void dealwithRead(SelectionKey key) {
try {
SocketChannel sc = (SocketChannel)key.channel();
System.out.println("读入数据");
r_bBuf.clear();
//将字节序列从此通道中读入给定的缓冲区r_bBuf
sc.read(r_bBuf);
r_bBuf.flip();
String msg = Charset.forName("UTF-8").decode(r_bBuf).toString();
if(msg.equalsIgnoreCase("time")) {
w_bBuf = ByteBuffer.wrap(getCurrentTime().getBytes("UTF-8"));
sc.write(w_bBuf);
w_bBuf.clear();
} else if(msg.equalsIgnoreCase("bye")) {
sc.write(ByteBuffer.wrap("已经与服务器断开连接".getBytes("UTF-8")));
sc.socket().close();
} else {
sc.write(ByteBuffer.wrap(msg.getBytes("UTF-8")));
}
System.out.println(msg);
System.out.println("处理完毕...");
r_bBuf.clear();
try {
Thread.currentThread();
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
private String getCurrentTime() {
Calendar date = Calendar.getInstance();
String time = "服务器当前时间:" +
date.get(Calendar.YEAR) + "-" +
date.get(Calendar.MONTH)+1 + "-" +
date.get(Calendar.DATE) + " " +
date.get(Calendar.HOUR) + ":" +
date.get(Calendar.MINUTE) + ":" +
date.get(Calendar.SECOND);
return time;
}
}
客户端代码实现:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
public class TestClient {
public static void main(String[] args) {
new MiniClient("localhost", 1982);
}
}
class MiniClient {
private SocketChannel sc;
private ByteBuffer w_bBuf;
private ByteBuffer r_bBuf = ByteBuffer.allocate(1024);
public MiniClient(String host, int port) {
try {
InetSocketAddress remote = new InetSocketAddress(host, port);
sc = SocketChannel.open();
sc.connect(remote);
if(sc.finishConnect()) {
System.out.println("已经与服务器成功建立连接...");
}
while(true) {
if(!sc.socket().isConnected()) {
System.out.println("已经与服务器失去了连接...");
return ;
}
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String str = br.readLine();
System.out.println("读入一行数据,开始发送...");
w_bBuf = ByteBuffer.wrap(str.getBytes("UTF-8"));
//将缓冲区中数据写入通道
sc.write(w_bBuf);
System.out.println("数据发送成功...");
w_bBuf.clear();
System.out.println("接收服务器端响应消息...");
try {
Thread.currentThread();
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
r_bBuf.clear();
//将字节序列从此通道中读入给定的缓冲区r_bBuf
sc.read(r_bBuf);
r_bBuf.flip();
String msg = Charset.forName("UTF-8").decode(r_bBuf).toString();
System.out.println(msg);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Thinking in java中的一个图片,刚找到的,比较清楚关系图: