接着上节课的内容
,我们继续来完成我们这个例子的编码
,那么接下来我们做到处理事件的函数
,handler这个函数
,那么handler这个方法的具体做的事情
,具体做的事情
,是我们在监听listen当中
,如果说这里边有事件准备就绪的通道
,那么我们在这里边选中它
,选中它以后
,我们对这些准备就绪的这些事件来进行处理
,所以说在这里边
,我们传了个准备就绪的这些事件
,所封装起来的这么一个SelectionKey这个类型
,那么把这个类型传过来
,那么我们接下来就对它进行分门别类的处理
,那么这边就如果说这个key里边的事件是我们新的客户端
,接入进来的事件准备好了
,那么我们就要对它进行处理
,那么在这里边这是第一个要处理
,应该是首先要处理的事件
,首先
,因为服务端与客户端
,它们之间在服务端处理连接进来的客户端
,那你第一件要处理的事情那就是接入客户端
,那么这里边key如果说是isAcceptable为true
,就表示有新的客户端进来
,那这里边表示有新的客户端
,有新的客户端进来
,有新的客户端进来我们就接
,怎么接呢
,我们首先要从这个SelectionKey当中
,把这个通道给取出来
,所以我们这key.channel
,把通道取出来
,通道取出来
,那么这个channel方法会给我返回SelectableChannel
,可选择的通道
,那么这个通道显然我们肯定不直接用它
,
我们用它的子类ServerSocketChannel
,所以说ServerSocketChannel是它的子类
,你要把一个父类类型的对象实例转换成它对应的子类
,这边需要强转
,来
,ServerSocketChannel
,这里边就serverSocketChannel吧
,等于
,这里边需要强转
,Alt加Enter键 强转
,强转出了这个ServerSocketChannel以后
,有了ServerSocketChannel
,我就可以正式的接入客户端
,那么怎么接入呢
,ServerSocketChannel.accept
,通过这个方法来接入
,当然这里边这个方法是要报出IO异常的
,这儿我们把它捕获一下
,那么这个try包裹的范围我就让
,这里面全部代码包裹了
,Ctrl+Shift+F格式化一下
,看到没有
,好 这里边
,这个是接入
,那么这个接入呢
,它会返回
,返回什么
,它会返回socketChannel
,那么返回的socketChannel就跟我的客户端是一对一对应的
,是一一对应的
,所以这里边把客户端的client
,客户端的这个Socket
,客户端的Socket
,我就把它当成客户端的Socket
,客户端的这个SocketChannel
,这是返回它
,返回它就代表客户端
,这个对象实例就代表客户端
,有了它我就可以跟客户端去做各种各样的事情
,所以说拿到它以后呢
,我们拿到它以后我们要进行处理
,要把客户端的socketChannel也要把它加入到
,也要把它设置为非阻塞模式
,然后把它注册到我的选择器里边
,
我们才能对它进一步的进行操作
,所以这边首先把它设置为非阻塞模式
,false
,然后再把它给加入注册到我的同一个选择器
,那么对于它来讲
,我们接入客户端
,接入客户端以后
,第一件事情就是对客户端发过来的信息进行读取
,所以说在这里边
,当它注册入我的选择器的时候
,我要对选择器对它感兴趣的事应该是
,应该是读这个事儿感兴趣
,应该是read这事感兴趣
,所以这边我们初始把连接进来的客户端的SocketChannel
,这个对象
,这个通道感兴趣的是什么呢
,是读取客户端发过来的信息
,那么这里边是这个逻辑
,那么这个读出来的信息
,我们就要把它在这里边
,这里边是接入情况下
,那么我们这边接入情况下
,就是这样子了
,接入情况下就是这样子
,那么接进来了
,然后我们把它设置为非阻塞模式
,然后注册到选择器里边
,设置选择器对它感兴趣的是读
,那么接下来就是
,因为我们这个handler它是放在了我循环监听的
,这个死循环里边
,所以说它第一次循环进来
,发现有通道进来
,就把这个通道
,第一次循环进来发现有通道
,有这个客户端连接进来
,那么就把这个客户端的通道拿到
,然后设置非阻塞模式
,然后把它放到了我的选择器里边
,然后我第二次循环
,第二次循环过来的时候
,
那么这个时候我们的选择器
,注册在选择器里面的通道
,就不仅仅只有我们刚刚最开始注册进来的
,ServerSocketChannel
,那么这个时候它里边既有ServerSocketChannel
,又有我们后面注册进去的客户端对应的socketChannel
,所以说这个时候我们循环
,下一次循环语句可能就遍历到我们这里边的
,这个clientSocket这个channel
,读事件准备就绪
,所以这里边这个客户端ServerSocketChannel的读事件可能准备就绪
,所以这边if
,我们还可以再加上else if
,else if什么呢
,我这里边的这个事件
,如果说它是isReadable读就绪准备好了
,那么这个时候就代表着我们客户端有信息发送给服务端上来了
,客户端有信息发送过来了
,我现在在服务端
,过来了
,那么客户端有信息发送过来了
,我就要处理
,我就要接收客户端的信息
,接收客户端信息首先通过Key.
,把这个channel通道先拿到
,这个时候的通道就不是ServerSocket通道
,而是与客户端一对一对应的那个socketChannel
,客户端对应的client
,客户端对应的这个SocketChannel
,应该是这个
,那么这里边看到没有
,这里边同样需要强转
,那么这个就是客户端对应的SocketChannel
,拿到这个客户端对应的套接字通道
,我就可以在这个套接字通道中去读数据
,
读数据我们就要用到我们的读缓冲区
,收缓冲区
,所以说我这边就先把我的读缓冲区
,接收信息的缓冲区readBuffer把它clear
,把它原来的数据清空
,原来的数据清空以后呢
,然后我们就可以去通过clientSocketChannel去读
,read方法
,然后这边readBuffer
,看到没有 这里边
,我们这个read就是把SocketChannel
,通道里边的数据往我的缓冲区里边写
,往我的缓冲区里面塞
,明白不
,好
,所以说这里边是这样子
,那么这个它会返回一个值
,当然这里边也是需要try
,也是需要捕获异常的
,那么也是IO异常
,然后e
,那么在这
,看到没有
,Ctrl+Shift+F格式化一下
,好
,这边是这样子
,那么我这里边读read这个方法又会给我返回一个整型
,返回的整型是我们从通道里边
,读到缓冲区里边的数据的字节数
,所以这里边我们给它一个int类型
,hasRead
,这边has已经读进去的这个计数
,hasRead等于它
,那么我们对这个hasRead进行判断
,如果说我们的hasRead大于0
,表示有数据进入我的缓冲区
,有数据进入我的缓冲区
,我就可以从缓冲区里边把这个数据拿出来
,所以说这里边有数据读进去了
,读进去了以后来我这边hasRead
,读进去了以后我先把我的这个readBuffer
,readBuffer读缓冲区
,把它进行flip 翻转
,
那么有关于这些什么是翻转
,然后缓冲区的清空 这些东西
,这些方法在我上门课程当中都详详细细的做了解释
,所以这些知识我不再重复
,你直接在这里边就把它用起来
,如果说你这些方法你还不甚明了
,那么你必须得去看看我前面上的那门IO模型
,NIO AIO入门这门课程
,对不
,所以说我在这里边本身是那门课 进阶课
,所以说我会默认你已经把那门课学过了
,然后再来那个
,所以在这门课里边一些讲过的东西
,我直接就用
,我不会再重复去讲
,那么这里边把这个翻转
,翻转完了以后
,我们就可以去把里边的数据读出来
,来 str
,里边的数据是什么呢
,里边的数据就可以直接读
,我们直接把readBuffer
,但这里边怎么样把这个readBuffer缓冲区
,直接把这缓冲区的数组弄出来呢
,我们可以这样子来获取
,String.valueOf
,然后这里边我们用我们的解析器
,字符解析器
,点什么呢
,decode 解析
,解析什么呢
,解析 把我们这readBuffer放进去
,那么它可以把缓冲区里边数据把它按照指定的字符集编码
,然后把它解码
,解码以后把它变成字符串
,然后出来
,那这里边你看它里边可以传入
,传入的是一个ByteBuffer
,看到没有
,直接传入ByteBuffer
,就可以把这个数据把它变成一个CharBuffer字符序列
,然后CharBuffer呢
,我们直接用String.valueOf就变成字符串了
,所以说这样的一个逻辑
,那么这个String str就是我们这个缓冲区里边的数据
,就是客户端向服务端发送过来的信息
,
那么客户端向服务端发送过来的信息都来了
,那么接下来的逻辑就是这个逻辑了
,对我们这个信息进行判断
,如果说它是
,这里边如果说我们接收到的这个信息
,它前后缀是USER_ROUND
,那么证明发送过来的信息是什么
,是我们的用户
,是用户信息的话
,来 我先拿到真正的用户信息
,这就跟我前面是一样的东西了
,来 我把真正的用户信息拿到
,那这个是我们去掉协议字符的方法
,来 我把这个去掉协议字符这方法也把它拿过来
,来 这边有些很多东西我们就可以直接拷贝了
,就不用真正的一点一点的写了
,来 在这里边
,来 去掉协议字符
,那么去掉协议字符
,拿到真正的用户名
,拿到真正的用户名以后
,然后我们判断
,这里边拿到真正用户名实质上我们这就
,实质上我们这就是什么
,就是直接实现登陆了
,实现登陆我们直接定义一个login一个方法来实现登录
,那么这里边传什么东西过去
,传一个SocketChannel
,这个clientSocketChannel
,这里边直接传一个clientSocketChannel
,然后把这str收到的信息直接传过去
,看到没有
,然后在这里边来 private
,然后private 实现登录 void
,然后login
,然后这里边传过来两个参数
,一个是socketChannel
,这边是客户端
,然后一个是我们客户端发过来的信息str
,好 然后在这里边
,