java nio之数据读写时无限循环分析与解决

    写这片文章是因为自己昨天刚解决了一个十个月前碰到的问题!当时苦于网上高手无人回答,也苦于自己当时没有时间去钻研为什么

   问题是:通过网上实例以及java网络编程这本书写java nio简单的测试服务器时发现,都是注册读写事件后然后分别处理相应的事件

就行了,这样本没错,可对于后续对注册事件的操作,再也没有看到与之相关实例与说明。然而,就这样完事以后,服务器端要么是

无限读事件与写事件有效,要么是客户端接收的数据是重复的好几条,在高并发时甚至上百上千。


   一般网络通讯程序是,客户端请求,然后服务端回复响应,即key.isReadable()时,服务器端接收请求,key.isWriteable()时,服

务端返回响应!一般我们在处理完接收后,我们就注册写事件,然后有写事件时处理写事件,正常网上的实例都是这样写的,可是这

样的话,客户端第二次以后发送时,服务器端再也没有进入到读事件中,还写事件回复的数据也很怪异,返回很多重复的数据。

再改进一点的是,写事件完事以后,又注册一个读事件,这样又可以读了,然后读了以后再注册写,这样反复重复,的确,能很好的

解决问题了。可是是因为什么原因呢?当时我是这样解决的,凑合用着,但是不知道为什么!

    昨天偶尔想起这个问题,然后查看mina源码时,发现其只注册过读事件,而对写事件并没有注册过,只是发现有一些

key.interestOps(SelectionKey.OP_WRITE)的操作,不是很明白,后来查看帮忙文档,知道这是管道当前感兴趣的事件时突然有些明

白了,后来又查看jdk源码,发现,每当重复注册时,都会检测事件是否已经注册过,如果已经注册过的事件,会把当前感兴趣的事

件切换成现在感兴趣的事件,这样所有的都明白了。

    即:管道注册事件,可以有四种事件,它可以注册所有的事件,但是管道每次只能对一种事件有效,即注册读事件时,此时只对读事

件有效,注册写事件时,此时只对写事件有效,这样上面的笨方法来回注册刚好达到这种效果,多的只是每次注册时的一次判断是否

已经注册过。当然我们也有更好的方法,那就是通过key.interestOps方法来切换当前感兴趣的事件,这样就可以避免每次注册时都

需要判断了。

    以上把问题与解决方法说明,现在附一下网上经常看到的服务器端实例!只是做了一些简单的修改。另外客户端网上很多也用非阻塞

实现的,我感觉没有必要,因为非阻塞只是为了解决高并发的问题。下面附上的客户端是我用socket写的一个简单实例!

 

 

//服务器

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是一个简单的使用Java NIO实现读写请求解析处理的Demo代码,并且解决了拆包问题: ```java import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; public class RequestHandler implements Runnable { private SocketChannel socketChannel; public RequestHandler(SocketChannel socketChannel) { this.socketChannel = socketChannel; } @Override public void run() { ByteBuffer buffer = ByteBuffer.allocate(1024); try { int bytesRead = socketChannel.read(buffer); while (bytesRead > 0) { buffer.flip(); while (buffer.hasRemaining()) { byte[] bytes = new byte[buffer.remaining()]; buffer.get(bytes); String request = new String(bytes); // 处理请求 String response = processRequest(request); // 送响应 ByteBuffer responseBuffer = ByteBuffer.wrap(response.getBytes()); socketChannel.write(responseBuffer); } buffer.clear(); bytesRead = socketChannel.read(buffer); } } catch (IOException e) { e.printStackTrace(); } } private String processRequest(String request) { // 处理请求 return "Hello, " + request; } } ``` 该代码使用了Java NIO中的SocketChannel读取请求并解析处理,使用ByteBuffer解决了拆包问题。在读取数据,首先读取到ByteBuffer中,然后将ByteBuffer中的数据转换成字节数组,并转换成字符串形式,再进行请求处理。在处理完请求后,将响应字符串转换成ByteBuffer,然后写入SocketChannel中送给客户端。循环读取请求,直到读取到的数据长度为0为止。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值