端口信息
public interface ServerInfo{
public static final int SERVER_PORT = 9999 ;//设置一个服务端口
public static final String SERVER_HOST = "localhost";//设置服务主机的名称
}
服务端
public class NIOEchoServer {
public void start() throws Exception {//启动服务器
// 1考虑到线程性能的分配处理,所以创建一个定长的线程池
ExecutorService service = Executors.newFixedThreadPool(32) ;//创建一个线程池
// 2如果要想实现服务端的开发,那么一定需要有一个服务端的Channel管理
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();//开启服务端处理通道
serverSocketChannel.configureBlocking(false);//设置为非阻塞模式
serverSocketChannel.bind(new InetSocketAddress(ServerInfo.SERVER_PORT));//在当前主机中的9999端口绑定服务
// 3 开启一个选择器,所有的Channel都注册到此选择器之中,利用此选择器的循环来判断是否有新的连接
Selector selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);//通道注册,连接的时候处理
// 4 、所有的用户的连接都要注册到当前的多路复用器上,那么就需要利用循环的模式来进行用户状态判断
int keySelect = 0 ; //保存用户的判断状态
while((keySelect = selector.select())>0){//持续进行等待,直到有用户连接上
Set<SelectionKey> selectionKeySet = selector.selectedKeys();//获取当前所有的连接的信息
Iterator<SelectionKey> selectionKeyIterator = selectionKeySet.iterator();
while (selectionKeyIterator.hasNext()){
SelectionKey selectionKey = selectionKeyIterator.next();//获取当前的处理状态
if(selectionKey.isAcceptable()){//当前为一个连接请求状态
SocketChannel socketChannel = serverSocketChannel.accept() ;//创建客户端通道
if(socketChannel !=null){
service.submit(new NIOEchoThread(socketChannel));//启动一个处理线程
}
}
selectionKeyIterator.remove();//已经进行了处理,所以不在需要做后续的轮询
}
}
service.shutdown();
serverSocketChannel.close();
}
public static void main(String[] args) throws Exception{
new NIOEchoServer().start();//主方法只是一个启动
}
}
class NIOEchoThread implements Runnable{
private SocketChannel socketChannel ;
private boolean flag = true ;
public NIOEchoThread(SocketChannel socketChannel)throws Exception{
this.socketChannel = socketChannel;
System.out.println("【客户端连接成功】连接的客户端的地址为:"+this.socketChannel.getRemoteAddress());
}
@Override
public void run() {
ByteBuffer buffer = ByteBuffer.allocate(50);//开辟一个50大小的缓冲区
try{
while (this.flag){//持续循环
buffer.clear();//清空缓冲区
int readCount =this.socketChannel.read(buffer) ;
String readMessage = new String(buffer.array(),0,readCount) ;
System.out.println("【服务器端收到的消息】"+readMessage);
String writeMessage = "【ECHO】"+readMessage;//设置回应的消息内容
if("exit".equalsIgnoreCase(readMessage)){
writeMessage = "【EXIT】拜拜,下次再见";
this.flag = false ;//结束循环
}
buffer.clear();//之前已经读取过数据了,所以先清空缓冲区
buffer.put(writeMessage.getBytes());//保存要回应的数据
buffer.flip();//重置缓冲区
this.socketChannel.write(buffer);
}
this.socketChannel.close();
}catch (Exception e){}
}
}
客户端
public class NIOEchoClient {
public void start()throws Exception{
SocketChannel socketChannel = SocketChannel.open() ;//开启Socket客户端通道
//通过服务器端的主机名称和IP地址进行服务器端的操作连接
socketChannel.connect(new InetSocketAddress(ServerInfo.SERVER_HOST,ServerInfo.SERVER_PORT));
ByteBuffer buffer = ByteBuffer.allocate(50);//通过缓冲区进行交互
boolean flag = true ;
while (flag){
buffer.clear() ;//清空缓冲区,因为该循环会持续执行
String str = InputUtil.getString("请输入要发送的信息:") ;
buffer.put(str.getBytes()) ;
buffer.flip() ;//缓冲区重置
socketChannel.write(buffer) ;
buffer.clear();//清空缓冲区等待接收回应信息
int readCount = socketChannel.read(buffer);//向缓冲区中读取数据
System.err.println(new String(buffer.array(),0,readCount));
if ("exit".equalsIgnoreCase(str)){
flag = false ;//循环结束
}
}
socketChannel.close();
}
public static void main(String[] args) throws Exception{
new NIOEchoClient().start();
}
}
class InputUtil { // 输入工具类
public static final BufferedReader KEYBOARD_INPUT = new BufferedReader(new InputStreamReader(System.in));
public static String getString(String prompt){
String result = null ;
while (result == null ||"".equals(result)){
try {
System.out.println(prompt);
result = KEYBOARD_INPUT.readLine();
} catch (IOException e) {
e.printStackTrace();
}
}
return result ;
}
}