写这片文章是因为自己昨天刚解决了一个十个月前碰到的问题!当时苦于网上高手无人回答,也苦于自己当时没有时间去钻研为什么
!
问题是:通过网上实例以及java网络编程这本书写java nio简单的测试服务器时发现,都是注册读写事件后然后分别处理相应的事件
就行了,这样本没错,可对于后续对注册事件的操作,再也没有看到与之相关实例与说明。然而,就这样完事以后,服务器端要么是
无限读事件与写事件有效,要么是客户端接收的数据是重复的好几条,在高并发时甚至上百上千。
一般网络通讯程序是,客户端请求,然后服务端回复响应,即key.isReadable()时,服务器端接收请求,key.isWriteable()时,服
务端返回响应!一般我们在处理完接收后,我们就注册写事件,然后有写事件时处理写事件,正常网上的实例都是这样写的,可是这
样的话,客户端第二次以后发送时,服务器端再也没有进入到读事件中,还写事件回复的数据也很怪异,返回很多重复的数据。
再改进一点的是,写事件完事以后,又注册一个读事件,这样又可以读了,然后读了以后再注册写,这样反复重复,的确,能很好的
解决问题了。可是是因为什么原因呢?当时我是这样解决的,凑合用着,但是不知道为什么!
昨天偶尔想起这个问题,然后查看mina源码时,发现其只注册过读事件,而对写事件并没有注册过,只是发现有一些
key.interestOps(SelectionKey.OP_WRITE)的操作,不是很明白,后来查看帮忙文档,知道这是管道当前感兴趣的事件时突然有些明
白了,后来又查看jdk源码,发现,每当重复注册时,都会检测事件是否已经注册过,如果已经注册过的事件,会把当前感兴趣的事
件切换成现在感兴趣的事件,这样所有的都明白了。
即:管道注册事件,可以有四种事件,它可以注册所有的事件,但是管道每次只能对一种事件有效,即注册读事件时,此时只对读事
件有效,注册写事件时,此时只对写事件有效,这样上面的笨方法来回注册刚好达到这种效果,多的只是每次注册时的一次判断是否
已经注册过。当然我们也有更好的方法,那就是通过key.interestOps方法来切换当前感兴趣的事件,这样就可以避免每次注册时都
需要判断了。
以上把问题与解决方法说明,现在附一下网上经常看到的服务器端实例!只是做了一些简单的修改。另外客户端网上很多也用非阻塞
实现的,我感觉没有必要,因为非阻塞只是为了解决高并发的问题。下面附上的客户端是我用socket写的一个简单实例!
//服务器