java 网络编程出问题

如此美丽的你 2020-06-04 01:00:48
基于nio单reactor 多工作线程模型

客户端

public class TcpClient {
public static void main(String[] args) throws IOException {
//开启网络channel
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1",88));
socketChannel.write(ByteBuffer.wrap("hello world".getBytes()));
while (true);

}
}


服务器



public class ReactorServer {
//开始监听服务
public static void start(Integer port){
try {
//1.服务端开启一个监听通道
ServerSocketChannel serverSocketChannel= ServerSocketChannel.open();
//2.绑定端口
serverSocketChannel.bind(new InetSocketAddress(port));
//3.设置为非阻塞
serverSocketChannel.configureBlocking(false);
//开启一个selector
Selector selector =Selector.open();
//注册channel 和要监听的时间
serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT,new Acceptor(selector,serverSocketChannel));

while (selector.select()>0){

Set<SelectionKey> selectionKeys = selector.selectedKeys();

Iterator<SelectionKey> iterator = selectionKeys.iterator();
//处理事件
while (iterator.hasNext()){

SelectionKey key = iterator.next();

Runnable handler =(Runnable) key.attachment();

handler.run();
//将事件移除
iterator.remove();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}

public static void main(String[] args) {
start(88);
}
}



Accepor


public class Acceptor implements Runnable {
private Selector selector;
private ServerSocketChannel serverSocketChannel;

public Acceptor(Selector selector,ServerSocketChannel serverSocketChannel){
this.selector=selector;
this.serverSocketChannel=serverSocketChannel;
}
@Override
public void run() {
try{
SocketChannel socketChannel = serverSocketChannel.accept();
//设置非阻塞
socketChannel.configureBlocking(false);
//注册selector,并交个dispatchhandler处理
System.out.println("有客户端连接进来");

socketChannel.register(selector,SelectionKey.OP_READ,new DispatchHandler(socketChannel));

}catch (IOException e){
e.printStackTrace();
}

}
}



DispatchHandler



public class DispatchHandler implements Runnable {
private static Executor executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()<<1);
private SocketChannel socketChannel;
public DispatchHandler(SocketChannel socketChannel){
this.socketChannel= socketChannel;
}
@Override
public void run() {
System.out.println("开启线程处理读写事件");
//通过线程池
executor.execute(new ReadHandler(socketChannel));
}
}


ReadHandler

public class ReadHandler implements Runnable {
private SocketChannel socketChannel;
public ReadHandler(SocketChannel socketChannel){
this.socketChannel=socketChannel;
}
@Override
public void run() {
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
Charset charset = Charset.forName("utf-8");
try {
while (socketChannel.read(byteBuffer)>0){
byteBuffer.flip();
System.out.println(charset.decode(byteBuffer).toString());
}
byteBuffer.clear();
//数据回写
socketChannel.write(ByteBuffer.wrap("收到".getBytes()));
}catch (IOException e){

e.printStackTrace();
}
}
}



下面是服务器运行结果
有客户端连接进来
开启线程处理读写事件
开启线程处理读写事件
开启线程处理读写事件
.....
hello world


为什么读事件会被重复执行 ,我上面都删除了嘛
...全文
206 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
冰思雨 2020-06-08
  • 打赏
  • 举报
回复
楼主说的读事件,其实是 可读事件。 也就是说,channel 可读的时候,就会生成这个事件,而不是说,收到数据之后会生成这个事件。 可读事件,和,可写事件,其实是一个意思,就是channel是否可以进行读取或者写入操作。 至于,是否能读到数据,或者,是否能写入数据,还要具体操作之后,才能确定。
  • 打赏
  • 举报
回复
上netty吧,自己写后面还不知道多少坑。
如此美丽的你 2020-06-04
  • 打赏
  • 举报
回复
引用 5 楼 tianfang 的回复:
你用的NIO具体是什么?是netty吗? 在什么操作系统测试的?
没用netty 就是java nio包 ,windows
tianfang 2020-06-04
  • 打赏
  • 举报
回复
你用的NIO具体是什么?是netty吗? 在什么操作系统测试的?
如此美丽的你 2020-06-04
  • 打赏
  • 举报
回复
引用 3 楼 tianfang 的回复:
[quote=引用 2 楼 如此美丽的你 的回复:] [quote=引用 1 楼 tianfang 的回复:] DispatchHandler  初始化 先在对象池中建立最小数量的对象
哪个对象池 是线程池吗[/quote] 就是这个,线程池     private static Executor executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()<<1); [/quote] 我把 这个设置成1 还是一样,我想了下 这可能是因为java nio 是基于epoll的 LT 水平触发造成的 虽然我开启了子线程去读 但线程并不是马上执行,selector 后面检测的时候 数据还没被读走 所有 又生成了READ 事件 不知道 有什么方法可以解决
tianfang 2020-06-04
  • 打赏
  • 举报
回复
引用 2 楼 如此美丽的你 的回复:
[quote=引用 1 楼 tianfang 的回复:] DispatchHandler  初始化 先在对象池中建立最小数量的对象
哪个对象池 是线程池吗[/quote] 就是这个,线程池     private static Executor executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()<<1);
如此美丽的你 2020-06-04
  • 打赏
  • 举报
回复
引用 1 楼 tianfang 的回复:
DispatchHandler  初始化 先在对象池中建立最小数量的对象
哪个对象池 是线程池吗
tianfang 2020-06-04
  • 打赏
  • 举报
回复
DispatchHandler  初始化 先在对象池中建立最小数量的对象

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧