最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

基于Netty,從零開發(fā)IM(三):編碼實踐篇(群聊功能)

2022-07-18 15:57 作者:nickkckckck  | 我要投稿

本文由作者“大白菜”分享,有較多修訂和改動。注意:本系列是給IM初學(xué)者的文章,IM老油條們還望海涵,勿噴!

1、引言

接上兩篇《IM系統(tǒng)設(shè)計篇》、《編碼實踐篇(單聊功能)》,本篇主要講解的是通過實戰(zhàn)編碼實現(xiàn)IM的群聊功能,內(nèi)容涉及群聊技術(shù)實現(xiàn)原理、編碼實踐等知識。

學(xué)習(xí)交流:

- 移動端IM開發(fā)入門文章:《新手入門一篇就夠:從零開發(fā)移動端IM》

- 開源IM框架源碼:https://github.com/JackJiang2011/MobileIMSDK(備用地址點此)

(本文已同步發(fā)布于:http://www.52im.net/thread-3981-1-1.html)

2、寫在前面

建議你在閱讀本文之前,務(wù)必先讀本系列的前兩篇《IM系統(tǒng)設(shè)計篇》、《編碼實踐篇(單聊功能)》,在著重理解IM系統(tǒng)的理論設(shè)計思路之后,再來閱讀實戰(zhàn)代碼則效果更好。

最后,在開始本文之前,請您務(wù)必提前了解Netty的相關(guān)基礎(chǔ)知識,可從本系列首篇《IM系統(tǒng)設(shè)計篇》中的“知識準(zhǔn)備”一章開始。

3、系列文章

本文是系列文章的第3篇,以下是系列目錄:

  • 《基于Netty,從零開發(fā)IM(一):IM系統(tǒng)設(shè)計篇》

  • 《基于Netty,從零開發(fā)IM(二):編碼實踐篇(單聊功能)》

  • 《基于Netty,從零開發(fā)IM(三):編碼實踐篇(群聊功能)》(* 本文)

  • 《基于Netty,從零開發(fā)IM(四):編碼實踐篇(系統(tǒng)優(yōu)化)》(稍后發(fā)布..?)

4、本篇概述

在上篇《編碼實踐篇(單聊功能)》中,我們主要實現(xiàn)了IM的單聊功能,本節(jié)主要是實現(xiàn)IM群聊功能。

本篇涉及的群聊核心功能,大致如下所示:

  • 1)登錄:每個客戶端連接服務(wù)端的時候,都需要輸入自己的賬號信息,以便和連接通道進(jìn)行綁定;

  • 2)創(chuàng)建群組:輸入群組 ID 和群組名稱進(jìn)行創(chuàng)建群組。需要先根據(jù)群組 ID 進(jìn)行校驗,判斷是否已經(jīng)存在了;

  • 3)查看群組:查看目前已經(jīng)創(chuàng)建的群組列表;

  • 4)加入群組:主要參數(shù)是群組 ID 和用戶 ID,用戶 ID 只需從 Channel 的綁定屬性里面獲取即。主要是判斷群組 ID 是否存在,如果存在還需要判斷該用戶 ID 是否已經(jīng)在群組里面了;

  • 5)退出群組:主要是判斷群組 ID 是否存在,如果存在則刪除相應(yīng)的關(guān)系;

  • 6)查看組成員:根據(jù)群組 ID 去查詢對應(yīng)的成員列表;

  • 7)群發(fā)消息:選擇某個群進(jìn)行消息發(fā)送,該群下的成員都能收到信息。主要判斷群組 ID 是否存在,如果存在再去獲取其對應(yīng)的成員列表。

5、群聊原理

其實群聊和單聊,整體上原理是一樣的,只是做了一下細(xì)節(jié)上的升級。

在首篇《IM系統(tǒng)設(shè)計篇》的“6、IM群聊思路設(shè)計”設(shè)計部分也做了詳細(xì)的說明了。

群聊的大概流程就是:根據(jù)群組 ID 查找到所有的成員集合,然后再遍歷找到每個成員對應(yīng)的連接通道。

具體的群聊架構(gòu)思路如下圖:

如上圖所示,群聊通訊流程技術(shù)原理如下:

  • 1)群聊和單聊整體上的思路一致:需要保存每個用戶和通道的對應(yīng)關(guān)系,方便后期通過用戶 ID 去查找到對應(yīng)的通道,再跟進(jìn)通道推送消息;

  • 2)群聊把消息發(fā)送給群員的原理:其實很簡單,服務(wù)端再保存另外一份映射關(guān)系,那就是聊天室和成員的映射關(guān)系。發(fā)送消息時,首先根據(jù)聊天室 ID 找到對應(yīng)的所有成員,然后再跟進(jìn)各個成員的 ID 去查找到對應(yīng)的通道,最后由每個通道進(jìn)行消息的發(fā)送;

  • 3)群成員加入某個群聊聊的時候:往映射表新增一條記錄,如果成員退群的時候則刪除對應(yīng)的映射記錄。

6、運行效果

補充說明:因為本系列文章主要目的是引導(dǎo)IM初學(xué)者在基于Netty的情況下,如何一步一步從零寫出IM的邏輯和思維能力,因而為了簡化編碼實現(xiàn),本篇中編碼實現(xiàn)的客戶端都是基于控制臺實現(xiàn)的(希望不要被嫌棄),因為理解技術(shù)的本質(zhì)顯然比炫酷的外在表現(xiàn)形式更為重要。

用戶登錄效果圖:

群組操作效果圖:

7、實體定義實戰(zhàn)

7.1 服務(wù)端實體

服務(wù)端映射關(guān)系的管理,分別是:

  • 1)登錄信息(用戶 ID 和通道);

  • 2)群組信息(群組 ID 和群組成員關(guān)系)。

主要通過兩個 Map 去維護(hù),具體如下:

public class ServerChatGroupHandler extends ChannelInboundHandlerAdapter {

????private static Map<Integer, Channel> map=new HashMap<Integer, Channel>();

????private static Map<Integer, Group> groups=new HashMap<Integer, Group>();

}

//組和成員列表關(guān)系實體

@Data

public class Group implements Serializable {

????private String groupName;

????private List<GroupMember> members=new ArrayList<GroupMember>();

}

//成員和連接通道的關(guān)系實體

public class GroupMember implements Serializable {

????private Integer userid;

????private Channel channel;

}

7.2 實體和指令關(guān)系

我們準(zhǔn)備好相應(yīng)的實體,以及實體和指令的映射關(guān)系,具體如下所示:

private static Map<Byte, Class<? extends BaseBean>> map=new HashMap<Byte,Class<? extends BaseBean>>();

????static{

????????//登錄的請求和響應(yīng)實體

????????map.put(1, LoginReqBean.class);

????????map.put(2, LoginResBean.class);

?

????????//創(chuàng)建群組的請求和響應(yīng)實體

????????map.put(3, GroupCreateReqBean.class);

????????map.put(4, GroupCreateResBean.class);

?

????????//查看群組的請求和響應(yīng)實體

????????map.put(5, GroupListReqBean.class);

????????map.put(6, GroupListResBean.class);

?

????????//加入群組的請求和響應(yīng)實體

????????map.put(7,GroupAddReqBean.class);

????????map.put(8,GroupAddResBean.class);

?

????????//退出群組的請求和響應(yīng)實體

????????map.put(9,GroupQuitReqBean.class);

????????map.put(10,GroupQuitResBean.class);

?

????????//查看成員列表的請求和響應(yīng)實體

????????map.put(11,GroupMemberReqBean.class);

????????map.put(12,GroupMemberResBean.class);

?

????????//發(fā)送響應(yīng)的實體(發(fā)送消息、發(fā)送響應(yīng)、接受消息)

????????map.put(13,GroupSendMsgReqBean.class);

????????map.put(14,GroupSendMsgResBean.class);

????????map.put(15,GroupRecMsgBean.class);

????}

通過下面這張圖,能看的更清晰一些:

?

8、Handler定義實戰(zhàn)

IM群聊功能的實現(xiàn),我們需要兩個兩個業(yè)務(wù) Handler:

  • 1)分別是客戶端(ClientChatGroupHandler);

  • 2)服務(wù)端(ServerChatGroupHandler)。

8.1 客戶端 Handler

客戶端 Handler,主要是通過判斷實體類型來做不同的業(yè)務(wù)操作,當(dāng)然也可以使用 SimpleChannelInboundHandler 去進(jìn)行 Handler 拆分。

public class ClientChatGroupHandler extends ChannelInboundHandlerAdapter {

????@Override

????public void channelActive(ChannelHandlerContext ctx) throws Exception {

????????//在鏈接就緒時登錄

????????login(ctx.channel());

????}

?

????//主要是“接受服務(wù)端”的響應(yīng)信息

????@Override

????public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

????????if(msg instanceof LoginResBean){

????????????LoginResBean res=(LoginResBean) msg;

????????????System.out.println("登錄響應(yīng):"+res.getMsg());

????????????if(res.getStatus()==0){

????????????????//登錄成功

?

????????????????//1.給通道綁定身份

????????????????ctx.channel().attr(AttributeKey.valueOf("userid")).set(res.getUserid());

?

????????????????//2.顯示操作類型【請看下面】

????????????????deal(ctx.channel());

????????????}else{

????????????????//登錄失敗,繼續(xù)登錄

????????????????login(ctx.channel());

????????????}

????????}else if(msg instanceof GroupCreateResBean){

????????????GroupCreateResBean res=(GroupCreateResBean)msg;

????????????System.out.println("創(chuàng)建響應(yīng)群組:"+res.getMsg());

?

????????}else if(msg instanceofGroupListResBean){

????????????GroupListResBean res=(GroupListResBean)msg;

????????????System.out.println("查看群組列表:"+res.getLists());

?

????????}elseif(msg instanceofGroupAddResBean){

????????????GroupAddResBean res=(GroupAddResBean)msg;

????????????System.out.println("加入群組響應(yīng):"+res.getMsg());

?

????????}elseif(msg instanceof GroupQuitResBean){

????????????GroupQuitResBean res=(GroupQuitResBean)msg;

????????????System.out.println("退群群組響應(yīng):"+res.getMsg());

?

????????}else if(msg instanceof GroupMemberResBean){

????????????GroupMemberResBean res=(GroupMemberResBean)msg;

????????????if(res.getCode()==1){

????????????????System.out.println("查看成員列表:"+res.getMsg());

????????????}else{

????????????????System.out.println("查看成員列表:"+res.getLists());

????????????}

?

????????}else if(msg instanceof GroupSendMsgResBean){

????????????GroupSendMsgResBean res=(GroupSendMsgResBean)msg;

????????????System.out.println("群發(fā)消息響應(yīng):"+res.getMsg());

?

????????}else if(msg instanceof GroupRecMsgBean){

????????????GroupRecMsgBean res=(GroupRecMsgBean)msg;

????????????System.out.println("收到消息fromuserid="+

???????????????????????????????res.getFromuserid()+

???????????????????????????????",msg="+res.getMsg());

????????}

????}

}

通過子線程循環(huán)向輸出控制臺輸出操作類型的方法,以下方法目前都是空方法,下面將詳細(xì)講解。

private void deal(final Channel channel){

????????final Scanner scanner=new Scanner(System.in);

????????new Thread(new Runnable() {

????????????public void run() {

????????????????while(true){

????????????????????System.out.println("請選擇類型:0創(chuàng)建群組,1查看群組,2加入群組,3退出群組,4查看群成員,5群發(fā)消息");

????????????????????int type=scanner.nextInt();

????????????????????switch(type){

????????????????????????case 0:

????????????????????????????createGroup(scanner,channel);

????????????????????????????break;

????????????????????????case 1:

????????????????????????????listGroup(scanner,channel);

????????????????????????????break;

????????????????????????case 2:

????????????????????????????addGroup(scanner,channel);

????????????????????????????break;

????????????????????????case 3:

????????????????????????????quitGroup(scanner,channel);

????????????????????????????break;

????????????????????????case 4:

????????????????????????????listMembers(scanner,channel);

????????????????????????????break;

????????????????????????case 5:

????????????????????????????sendMsgToGroup(scanner,channel);

????????????????????????????break;

????????????????????????default:

????????????????????????????System.out.println("輸入的類型不存在!");

????????????????????}

????????????????}

????????????}

????????}).start();

????}

8.2 服務(wù)端 Handler

服務(wù)端 Handler,主要是通過判斷實體類型來做不同的業(yè)務(wù)操作,當(dāng)然也可以使用 SimpleChannelInboundHandler 去進(jìn)行 Handler 拆分。

以下方法目前都是空方法,下面將詳細(xì)講解。

public class ServerChatGroupHandler extends ChannelInboundHandlerAdapter {

????private static Map<Integer, Channel> map=new HashMap<Integer, Channel>();

????private static Map<Integer, Group> groups=new HashMap<Integer, Group>();

?

????@Override

????public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

????????if(msg instanceof LoginReqBean) {

????????????//登錄

????????????login((LoginReqBean) msg, ctx.channel());

????????}else if(msg instanceof GroupCreateReqBean){

????????????//創(chuàng)建群組

????????????createGroup((GroupCreateReqBean)msg,ctx.channel());

????????}else if(msg instanceof GroupListReqBean){

????????????//查看群組列表

????????????listGroup((GroupListReqBean)msg,ctx.channel());

????????}else if(msg instanceof GroupAddReqBean){

????????????//加入群組

????????????addGroup((GroupAddReqBean)msg,ctx.channel());

????????}else if(msg instanceof GroupQuitReqBean){

????????????//退出群組

????????????quitGroup((GroupQuitReqBean)msg,ctx.channel());

????????}else if(msg instanceof GroupMemberReqBean){

????????????//查看成員列表

????????????listMember((GroupMemberReqBean)msg,ctx.channel());

????????}else if(msg instanceof GroupSendMsgReqBean){

????????????//消息發(fā)送

????????????sendMsg((GroupSendMsgReqBean) msg,ctx.channel());

????????}

????}

}

9、具體功能編碼實戰(zhàn)

9.1 創(chuàng)建群組

客戶端請求:

private void createGroup(Scanner scanner,Channel channel){

????????System.out.println("請輸入群組ID");

????????Integer groupId=scanner.nextInt();

????????System.out.println("請輸入群組名稱");

????????String groupName=scanner.next();

?

????????GroupCreateReqBean bean=new GroupCreateReqBean();

????????bean.setGroupId(groupId);

????????bean.setGroupName(groupName);

????????channel.writeAndFlush(bean);

????}

服務(wù)端處理:

public class ServerChatGroupHandler extends ChannelInboundHandlerAdapter {

????private static Map<Integer, Channel> map=new HashMap<Integer, Channel>();

????private static Map<Integer, Group> groups=new HashMap<Integer, Group>();

?

????private void createGroup(GroupCreateReqBean bean,Channel channel){

????????//定義一個響應(yīng)實體

????????GroupCreateResBean res=new GroupCreateResBean();

????????//查詢groups是否已經(jīng)存在

????????Group group=groups.get(bean.getGroupId());

????????//判斷是否已經(jīng)存在

????????if(group==null){

????????????//定義群組實體

????????????Group g=new Group();

????????????//定義一個集合,專門存儲成員

????????????List<GroupMember> members=new ArrayList<GroupMember>();

????????????//屬性賦值

????????????g.setGroupName(bean.getGroupName());

????????????g.setMembers(members);

????????????//添加到Map里面

????????????groups.put(bean.getGroupId(),g);

?

????????????//響應(yīng)信息

????????????res.setCode(0);

????????????res.setMsg("創(chuàng)建群組成功");

????????}else{

????????????res.setCode(1);

????????????res.setMsg("該群組已經(jīng)存在!");

????????}

????????channel.writeAndFlush(res);

????}

}

9.2 查看群組

客戶端請求:

private void listGroup(Scanner scanner,Channel channel){

????GroupListReqBean bean=new GroupListReqBean();

????bean.setType("list");

????channel.writeAndFlush(bean);

}

服務(wù)端處理:

public class ServerChatGroupHandler extends ChannelInboundHandlerAdapter {

????private static Map<Integer, Channel> map=new HashMap<Integer, Channel>();

????private static Map<Integer, Group> groups=new HashMap<Integer, Group>();

?

????private void listGroup(GroupListReqBean bean,Channel channel){

????????if("list".equals(bean.getType())){

????????????//定義一個響應(yīng)實體

????????????GroupListResBean res=new GroupListResBean();

????????????//定義一個集合

????????????List<GroupInfo> lists=new ArrayList<GroupInfo>();

????????????//變量groups Map集合

????????????for(Map.Entry<Integer, Group> entry : groups.entrySet()){

????????????????Integer mapKey = entry.getKey();

????????????????Group mapValue = entry.getValue();

????????????????GroupInfo gi=new GroupInfo();

????????????????gi.setGroupId(mapKey);

????????????????gi.setGroupName(mapValue.getGroupName());

????????????????lists.add(gi);

????????????}

????????????//把集合添加到響應(yīng)實體里面

????????????res.setLists(lists);

????????????//開始寫到客戶端

????????????channel.writeAndFlush(res);

????????}

????}

}

9.3 加入群組

客戶端請求:

private void addGroup(Scanner scanner,Channel channel){

????System.out.println("請輸入加入的群組ID");

????int groupId=scanner.nextInt();

????Integer userId=(Integer) channel.attr(AttributeKey.valueOf("userid")).get();

?

????GroupAddReqBean bean=new GroupAddReqBean();

????bean.setUserId(userId);

????bean.setGroupId(groupId);

????channel.writeAndFlush(bean);

}

服務(wù)端處理:

public class ServerChatGroupHandler extends ChannelInboundHandlerAdapter {

????private static Map<Integer, Channel> map=new HashMap<Integer, Channel>();

????private static Map<Integer, Group> groups=new HashMap<Integer, Group>();

?

????private void addGroup(GroupAddReqBean bean,Channel channel){

????????GroupAddResBean res=new GroupAddResBean();

????????//1.根據(jù)“群組ID”獲取對應(yīng)的“組信息”

????????Group group=groups.get(bean.getGroupId());

????????//2.“群組”不存在

????????if(group==null){

????????????res.setCode(1);

????????????res.setMsg("groupId="+bean.getGroupId()+",不存在!");

????????????channel.writeAndFlush(res);

????????????return;

????????}

????????//3.“群組”存在,則獲取其底下的“成員集合”

????????List<GroupMember> members=group.getMembers();

????????boolean flag=false;

????????//4.遍歷集合,判斷“用戶”是否已經(jīng)存在了

????????for(GroupMember gm:members){

????????????if(gm.getUserid()==bean.getUserId()){

????????????????flag=true;

????????????????break;

????????????}

????????}

????????if(flag){

????????????res.setCode(1);

????????????res.setMsg("已經(jīng)在群組里面,無法再次加入!");

????????}else{

????????????//1.用戶信息

????????????GroupMember gm=new GroupMember();

????????????gm.setUserid(bean.getUserId());

????????????gm.setChannel(channel);

?

????????????//2.添加到集合里面

????????????members.add(gm);

?

????????????//3.給“群組”重新賦值

????????????group.setMembers(members);

?

????????????res.setCode(0);

????????????res.setMsg("加入群組成功");

????????}

????????channel.writeAndFlush(res);

????}

}

9.4 退出群組

客戶端請求:

private void quitGroup(Scanner scanner,Channel channel){

????System.out.println("請輸入退出的群組ID");

????int groupId=scanner.nextInt();

????Integer userId=(Integer) channel.attr(AttributeKey.valueOf("userid")).get();

?

????GroupQuitReqBean bean=new GroupQuitReqBean();

????bean.setUserId(userId);

????bean.setGroupId(groupId);

????channel.writeAndFlush(bean);

}

服務(wù)端處理:

public class ServerChatGroupHandler extends ChannelInboundHandlerAdapter {

????private static Map<Integer, Channel> map=new HashMap<Integer, Channel>();

????private static Map<Integer, Group> groups=new HashMap<Integer, Group>();

?

????private void quitGroup(GroupQuitReqBean bean,Channel channel){

????????GroupQuitResBean res=new GroupQuitResBean();

?

????????//1.根據(jù)“群組ID”獲取對應(yīng)的“組信息”

????????Group group=groups.get(bean.getGroupId());

????????if(group==null){

????????????//2.群組不存在

????????????res.setCode(1);

????????????res.setMsg("groupId="+bean.getGroupId()+",不存在!");

????????????channel.writeAndFlush(res);

????????????return;

????????}

????????//3.群組存在,則獲取其底下“成員集合”

????????List<GroupMember> members=group.getMembers();

????????//4.遍歷集合,找到“當(dāng)前用戶”在集合的序號

????????int index=-1;

????????for(inti=0;i<members.size();i++){

????????????if(members.get(i).getUserid()==bean.getUserId()){

????????????????index=i;

????????????????break;

????????????}

????????}

????????//5.如果序號等于-1,則表示“當(dāng)前用戶”不存在集合里面

????????if(index==-1){

????????????res.setCode(1);

????????????res.setMsg("userid="+bean.getUserId()+",不存在該群組里面!");

????????????channel.writeAndFlush(res);

????????????return;

????????}

????????//6.從集合里面刪除“當(dāng)前用戶”

????????members.remove(index);

????????//7.給“群組”的“成員列表”重新賦值

????????group.setMembers(members);

????????res.setCode(0);

????????res.setMsg("退出群組成功");

????????channel.writeAndFlush(res);

????}

}

9.5 查看群組成員

客戶端請求:

private void listMembers(Scanner scanner,Channel channel){

????System.out.println("請輸入群組ID:");

????int groupId=scanner.nextInt();

?

????GroupMemberReqBean bean=new GroupMemberReqBean();

????bean.setGroupId(groupId);

????channel.writeAndFlush(bean);

}

服務(wù)端處理:

public class ServerChatGroupHandler extends ChannelInboundHandlerAdapter {

????private static Map<Integer, Channel> map=new HashMap<Integer, Channel>();

????private static Map<Integer, Group> groups=new HashMap<Integer, Group>();

?

????private void listMember(GroupMemberReqBean bean,Channel channel){

????????GroupMemberResBean res=new GroupMemberResBean();

????????List<Integer> lists=new ArrayList<Integer>();

????????//1.根據(jù)“群組ID”獲取對應(yīng)的“組信息”

????????Group group=groups.get(bean.getGroupId());

????????if(group==null){

????????????//2.查詢的群組不存在

????????????res.setCode(1);

????????????res.setMsg("groupId="+bean.getGroupId()+",不存在!");

????????????channel.writeAndFlush(res);

????????}else{

????????????//3.群組存在,則變量其底層的成員

????????????for(Map.Entry<Integer, Group> entry : groups.entrySet()){

????????????????Group g = entry.getValue();

????????????????List<GroupMember> members=g.getMembers();

????????????????for(GroupMember gm:members){

????????????????????lists.add(gm.getUserid());

????????????????}

????????????}

?

????????????res.setCode(0);

????????????res.setMsg("查詢成功");

????????????res.setLists(lists);

????????????channel.writeAndFlush(res);

?????????}

????}

}

9.6 群發(fā)消息

客戶端請求:

private void sendMsgToGroup(Scanner scanner,Channel channel){

????System.out.println("請輸入群組ID:");

????int groupId=scanner.nextInt();

?

????System.out.println("請輸入發(fā)送消息內(nèi)容:");

????String msg=scanner.next();

?

????Integer userId=(Integer) channel.attr(AttributeKey.valueOf("userid")).get();

?

????GroupSendMsgReqBean bean=new GroupSendMsgReqBean();

????bean.setFromuserid(userId);

????bean.setTogroupid(groupId);

????bean.setMsg(msg);

????channel.writeAndFlush(bean);

}

服務(wù)端處理:

public class ServerChatGroupHandler extends ChannelInboundHandlerAdapter {

????private static Map<Integer, Channel> map=new HashMap<Integer, Channel>();

????private static Map<Integer, Group> groups=new HashMap<Integer, Group>();

?

????privatevoidsendMsg(GroupSendMsgReqBean bean,Channel channel){

????????GroupSendMsgResBean res=new GroupSendMsgResBean();

?

????????//1.根據(jù)“群組ID”獲取對應(yīng)的“組信息”

????????Group group=groups.get(bean.getTogroupid());

?

????????//2.給“發(fā)送人”響應(yīng),通知其發(fā)送的消息是否成功

????????if(group==null){

????????????res.setCode(1);

????????????res.setMsg("groupId="+bean.getTogroupid()+",不存在!");

????????????channel.writeAndFlush(res);

????????????return;

????????}else{

????????????res.setCode(0);

????????????res.setMsg("群發(fā)消息成功");

????????????channel.writeAndFlush(res);

????????}

????????//3.根據(jù)“組”下面的“成員”,變量并且逐個推送消息

????????List<GroupMember> members=group.getMembers();

????????for(GroupMember gm:members){

????????????GroupRecMsgBean rec=new GroupRecMsgBean();

????????????rec.setFromuserid(bean.getFromuserid());

????????????rec.setMsg(bean.getMsg());

????????????gm.getChannel().writeAndFlush(rec);

????????}

????}

}

10、本篇小結(jié)

本篇中涉及的功能點稍微有點多,主要是實現(xiàn)了群聊的幾個核心功能,分別是:創(chuàng)建群組、查看群組列表、加入群組、退出群組、查看成員列表、群發(fā)消息。

這些功能經(jīng)過拆解,看起來就不是那么復(fù)雜了,希望大家都可以親自動手實現(xiàn)一遍,加深理解,提高學(xué)習(xí)效果。

實際上,真正的產(chǎn)品級IM中,群聊涉及的技術(shù)細(xì)節(jié)是非常多的,有興趣可以詳讀下面這幾篇:

  • IM群聊消息如此復(fù)雜,如何保證不丟不重?

  • 移動端IM中大規(guī)模群消息的推送如何保證效率、實時性?

  • 關(guān)于IM即時通訊群聊消息的亂序問題討論

  • IM群聊消息究竟是存1份(即擴(kuò)散讀)還是存多份(即擴(kuò)散寫)?

  • 一套高可用、易伸縮、高并發(fā)的IM群聊、單聊架構(gòu)方案設(shè)計實踐

  • 網(wǎng)易云信技術(shù)分享:IM中的萬人群聊技術(shù)方案實踐總結(jié)

  • 阿里電商IM消息平臺,在群聊、直播場景下的技術(shù)實踐

  • 企業(yè)微信的IM架構(gòu)設(shè)計揭秘:消息模型、萬人群、已讀回執(zhí)、消息撤回等

  • 融云IM技術(shù)分享:萬人群聊消息投遞方案的思考和實踐

11、參考資料

[1]?手把手教你用Netty實現(xiàn)心跳機(jī)制、斷線重連機(jī)制

[2]?自已開發(fā)IM很難?手把手教你擼一個Andriod版IM

[3]?基于Netty,從零開發(fā)一個IM服務(wù)端

[4]?拿起鍵盤就是干,教你徒手開發(fā)一套分布式IM系統(tǒng)

[5]?正確理解IM長連接、心跳及重連機(jī)制,并動手實現(xiàn)

[6]?手把手教你用Go快速搭建高性能、可擴(kuò)展的IM系統(tǒng)

[7]?手把手教你用WebSocket打造Web端IM聊天

[8]?萬字長文,手把手教你用Netty打造IM聊天

[9]?基于Netty實現(xiàn)一套分布式IM系統(tǒng)

[10]?基于Netty,搭建高性能IM集群(含技術(shù)思路+源碼)

[11]?SpringBoot集成開源IM框架MobileIMSDK,實現(xiàn)即時通訊IM聊天功能

(本文已同步發(fā)布于:http://www.52im.net/thread-3981-1-1.html)


基于Netty,從零開發(fā)IM(三):編碼實踐篇(群聊功能)的評論 (共 條)

分享到微博請遵守國家法律
达日县| 兴安盟| 鄂州市| 庆城县| 杨浦区| 光泽县| 乐至县| 旌德县| 化州市| 京山县| 郧西县| 陇川县| 东安县| 盱眙县| 自治县| 米泉市| 南江县| 翼城县| 开阳县| 盐源县| 灵璧县| 嘉善县| 炎陵县| 靖边县| 弥渡县| 平湖市| 定安县| 腾冲县| 库车县| 克拉玛依市| 辉县市| 都江堰市| 桦川县| 始兴县| 莎车县| 娄底市| 措勤县| 桃江县| 义乌市| 吉木乃县| 大丰市|