java echo server_使用NIO编写一个echo服务

实现效果

1、客户端:可以接收用户键盘的输入值,当用户输入回收键则把消息发送给服务端。

2、服务端:监听客户端连接,客户端发送消息过来后,服务端把客户端的消息响应给客户端。

服务端

NIO使用的是IO复用模型,服务端可以通过一个线程监听多个客户端连接,客户端连接上来后,服务端只需要把通道和多路复用器建立一个绑定关系,然后服务端向多路复用器注册自己感兴趣的事件,最后服务端通过不断的调用多路复用器select方法来监听是否有感兴趣的事件就绪,当有事件就绪时,服务端再从根据事件类型处理对应的事件。

服务端流程:

1、启动一个socket服务

创建管道、绑定端口、设置IO模式、创建多路复用器,把管道和多路复用器建立绑定关系,往多路复用器上注册客户端连接事件。

2、监听客户端就绪事件

建一个线程专门监听多路复用器的就绪事件,通过循环调用selector.select ()方法来监听是否有连接事件的到来,当监听到客户有事件就绪时调用业务处理方法去处理对应事件类型的业务。

3、处理事件

当监听到客户端连接就绪事件时,把连接注册到通道上,并注册监听后续的读取事件。

当监听到客户端读取就绪事件时,从通道里读取对应的消息,然后把消息响应给服务端。

服务启动类(启动一个socket服务)

import java.io.IOException;

import java.net.InetSocketAddress;

import java.nio.channels.*;

public class NioEchoServer{

//服务管道,用来向客户端接收或发送数据 private ServerSocketChannel serverSocketChannel;

//多路复用器,用来向通道注册连接和监听通道事件 private Selector selector;

//服务端口 private Integer port;

public NioEchoServer(Integer port) {

this.port=port;

initServer();

}

/*** 1、初始化参数管道、多路复用器、注册连接事件*/

private void initServer() {

try {

//开启服务管道 serverSocketChannel= ServerSocketChannel.open();

//开启多路复用选择器 selector=Selector.open();

//绑定端口 serverSocketChannel.socket().bind(new InetSocketAddress(port));

//设置IO模式为非阻塞 serverSocketChannel.configureBlocking(false);

//把管道注册到多路复用选择器上,监听客户端连接事件 serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);

} catch (IOException e) {

e.printStackTrace();

}

}

/*** 2、开启一个线程监听selector的事件*/

public void start(){

new Thread(new NioSelectorHandler(selector)).start();

System.out.println("服务启动port="+port);

}

public static void main(String[] args) {

NioEchoServer myNioServer=new NioEchoServer(9090);

myNioServer.start();

}

}

事件轮询处理类(监听客户端就绪事件,处理事件就绪事件)

import java.io.IOException;

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.util.Iterator;

import java.util.Set;

public class NioSelectorHandler implements Runnable{

private Selector selector;

//读取数据缓存 private ByteBuffer readBuffer;

//发送数据缓存 private ByteBuffer writeBuffer;

public NioSelectorHandler(Selector selector) {

this.selector = selector;

this.readBuffer=ByteBuffer.allocate(1024);

this.writeBuffer=ByteBuffer.allocate(1024);

}

public void run() {

while (true){

try {

//3、循环调用selector 监听管道中是否有活跃事件 int keyNumber=selector.select();

//通道活跃事件集合 Set selectionKeys=selector.selectedKeys();

Iterator iterator=selectionKeys.iterator();

SelectionKey selectionKey=null;

while (iterator.hasNext()){

System.out.println("一个事件就绪");

selectionKey=(SelectionKey)iterator.next();

//4、处理就绪事件 process(selectionKey);

//移出事件 iterator.remove();

}

} catch (Exception e) {

e.printStackTrace();

}

}

}

public void process(SelectionKey selectionKey){

try {

//通道是否有效 if(!selectionKey.isValid()){

return ;

}

//处理客户端连接就绪事件 if( selectionKey.isAcceptable()){

System.out.println("与客户端建立连接");

ServerSocketChannel scc=(ServerSocketChannel)selectionKey.channel();

//服务端与客户端建立连接 SocketChannel sc=scc.accept();

sc.configureBlocking(false);

//连接成功后,往selector 注册对应通道的OP_READ读取事件 sc.register(selector,SelectionKey.OP_READ);

}

//处理数据读取就绪事件 if(selectionKey.isReadable()) {

SocketChannel soketchannel = (SocketChannel) selectionKey.channel();

//将通道中的书读取到缓存x/读取之前先清空缓存 readBuffer.clear();

int size = soketchannel.read(readBuffer);

readBuffer.flip();

if (size > 0) {

byte[] bytes = new byte[readBuffer.remaining()];

readBuffer.get(bytes);

String content = new String(bytes);

System.out.println("收到消息:" + content);

//响应消息客户端消息 writeBuffer.clear();

writeBuffer.put(content.getBytes("UTF-8"));

writeBuffer.flip();

soketchannel.write(writeBuffer);

}else if(size<0){

System.out.println("与客户端连接断开");

//关闭通道 soketchannel.close();

//关闭连接 selectionKey.cancel();

}else{

//没有数据 return ;

}

}

} catch (IOException e) {

e.printStackTrace();

}

}

}

客户端

import java.io.*;

import java.net.InetSocketAddress;

import java.nio.ByteBuffer;

import java.nio.channels.SocketChannel;

/*** Created by Administrator on 2020/4/10.*/

public class NioEchoClient {

private SocketChannel socketChannel;

//服务连接端口 private Integer port;

//服务端连接地址 private String host;

//读取数据缓存 private ByteBuffer readBuffer;

//发送数据缓存 private ByteBuffer writeBufer;

public NioEchoClient(String host,Integer port) {

this.host=host;

this.port=port;

readBuffer=ByteBuffer.allocate(1024);

writeBufer=ByteBuffer.allocate(1024);

}

public void connect(){

try {

//开启服务管道 socketChannel= SocketChannel.open();

//与服务端建立连接 socketChannel.connect(new InetSocketAddress(host,port));

//读取控制台输入内容 BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(System.in));

while (true){

//往服务端发送数据 String line=bufferedReader.readLine();

if(line!=null && !line.equals("")){

//把数据添加到缓存 writeBufer.put(line.getBytes());

//重置游标 writeBufer.flip();

socketChannel.write(writeBufer);

//清空缓存数据 writeBufer.clear();

System.out.println("发送数据完毕");

}

//从服务端读取数据 readBuffer.clear();

int size=socketChannel.read(readBuffer);

if(size>0){

readBuffer.flip();

byte[] result=new byte[readBuffer.remaining()];

//把数据读取到数组 readBuffer.get(result);

String content=new String(result);

System.out.println("服务端响应:"+content);

}

}

} catch (IOException e) {

e.printStackTrace();

}

}

public static void main(String[] args) {

NioEchoClient nioEchoClient=new NioEchoClient("127.0.0.1",9090);

nioEchoClient.connect();

}

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值