Clients chat with each other_java

今天发点人文的东西,这三张图都拍摄于拉卜楞寺。

Clients chat with each other_java_02

Clients chat with each other_java_03


Clients chat with each other_java_04

王皓的GitHub:https://github.com/TenaciousDWang  

     

        在学习了Netty一些列的组件之后,今天我们来实战一下,写一下客户端互相聊天的功能。


        首先我们来分析一下这个功能应该怎么实现,假设现在有三个客户端登陆,首先我们需要将这三个客户端ID与对应的连接存到一个容器里,这里我们使用线程安全的ConcurrentHashMap以Key-Value的形式来存储这对映射关系。


        接下来我们分析一下互聊如何实现,假设A端要与B端聊天,A端发送数据包应该具有接受信息用户B的ID与聊天信息内容,服务端收到数据包后,根据数据包内接受信息用户ID从刚才的容器中找到对应的连接,然后将聊天信息写入连接,客户端B接收消息并打印到控制台,流程结束。


        接下来我们先来实现第一个处理登陆信息的功能,首先我们先创建一个Session对象,用于存储用户信息。


Clients chat with each other_java_05


        接下来我们来抽取出一个工具类,用来操作Session对象及绑定连接,接触连接等。


Clients chat with each other_java_06


        我们定义一个userIdChannelMap容器用来存储Session对象及对应的连接,创建一个绑定方法bindSession用来向容器里存放映射关系,同时给该连接绑定一个叫session的Attributes标识,里面泛型限定是一个session。


Clients chat with each other_java_07


        有绑定就有解除绑定功能,添加一个unBindSession方法当没有登录时用来移除容器里的映射关系,创建一个getSession方法用来从连接中获取用户信息,创建一个getChannel方法用来根据用户标识,获取连接用于发送消失时。


Clients chat with each other_java_08


        接下来我们改造一下之前写的用于处理登陆请求的Handler。登陆时我们先随机给用户生成一个id,并返回给用户,当然真正生产时,还是需要从数据库等持久化设施中读取的,这里我们把更多的时间放在netty上,将用户信息存入Session并与当前连接绑定,用户断线后移除绑定。


        这样在用户登录时,我们就将用户信息与当前连接绑定,并存入内存当中,以备使用。


        接下来我们来实现向一个客户端发送消息的功能,首先我们来定义一个发送消息数据包,里面需要定义一个指向用户ID变量,和消息变量。


Clients chat with each other_java_09


        接下来我们在服务端写一个Handler来处理这个消息请求。当服务端读取到消息时,从数据包提取用户ID去容器里查找,找到后给对应的连接写入当前客户端发送来的消息即可,如果容器中无法找到对应的连接,则说明对方不在线,消息发送失败。


Clients chat with each other_java_10


        对方客户端相对简单,只需要将接受到的消息,打印到控制台即可。


Clients chat with each other_java_11


        最后我们回到客户端稍微改造一下,写一个发送消息的功能。


Clients chat with each other_java_12

        

        首先登陆,如果已经登陆,我们可以在控制台输入消息接收方的 userId,然后输入一个空格,再输入消息的具体内容,然后,我们就可以构建一个消息数据包,发送到服务端。