Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >全平台开源即时通讯IM聊天框架MobileIMSDK的服务端开发指南,支持鸿蒙NEXT

全平台开源即时通讯IM聊天框架MobileIMSDK的服务端开发指南,支持鸿蒙NEXT

原创
作者头像
JackJiang
发布于 2025-05-16 22:30:08
发布于 2025-05-16 22:30:08
15400
代码可运行
举报
运行总次数:0
代码可运行

写在前面

在着手基于MobileIMSDK开发自已的即时通讯应用前,建议以Demo工程为脚手架,快速上手MobileIMSDK!

Demo工程主要用于演示SDKAPI调用等,它位于SDK完整下载包的如下目录:

如上图目录demo_src/Server/所示,这是一个完整的IDEA工程(含完整的可运行Demo源码)。

如果你只是想看看Demo的话,可以下载编译好的Demo包立即体验:它位于SDK完整下载包的 demo_binary/server/ 目录下。

第一部分:集成准备

第1步:下载SDK并找到lib包

① 马上下载:

最新版打包下载:Github点此进入Gitee同步托管Gitcode同步托管),或者前往 MobileIMSDK的Github自行同步代码。

② 找到lib包:

位于SDK完整下载包的 sdl_binary/Server/ 目录下:

第2步:引用lib包和依赖库

提示:MobileIMSDK的Server端lib包支持Java 1.7(含)及以上版本。

2.1 引用lib包(IDEA工程,本地jar方式)

① IDEA中如何引用第3方本地jar包?

跟所有Java工程一样引用jar包很简单,如果没试过,请查看:IDEA引入本地jar包的两种方法 或自行百度查找资料。

② 以MobileIMSDK Server的Demo工程为例,结果如下图:

2.2 引用lib包(IDEA工程,Maven方式)

① IDEA中如何在pom.xml中引用本地jar包和依赖库?

在pom.xml加入以下配置:(以下配置参考自IM产品 RainbowChat

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 1 <dependencies>
 2    
 3   <!-- 依赖的开源JSON库Gson -->
 4   <dependency>
 5     <groupId>com.google.code.gson</groupId>
 6     <artifactId>gson</artifactId>
 7     <version>2.8.9</version>
 8   </dependency>
 9  
10   <!-- 依赖的log4j日志框架的实用组合 -->
11   <dependency>
12     <groupId>org.apache.logging.log4j</groupId>
13     <artifactId>log4j-api</artifactId>
14     <version>2.23.1</version>
15   </dependency>
16   <dependency>
17     <groupId>org.apache.logging.log4j</groupId>
18     <artifactId>log4j-core</artifactId>
19     <version>2.23.1</version>
20   </dependency>
21   <dependency>
22     <groupId>org.apache.logging.log4j</groupId>
23     <artifactId>log4j-slf4j-impl</artifactId>
24     <version>2.23.1</version>
25   </dependency>
26  
27   <!-- 依赖的RabbitMQ中间件的java客户端库,用于与MobileIMSDK-Web产品进行消息互通时 -->
28   <dependency>
29     <groupId>com.rabbitmq</groupId>
30     <artifactId>amqp-client</artifactId>
31     <version>5.20.0</version>
32   </dependency>
33  
34   <!-- 依赖的netty库 -->
35   <dependency>
36     <groupId>io.netty</groupId>
37     <artifactId>netty-all</artifactId>
38     <version>4.1.67.Final</version>
39   </dependency>
40  
41   <!-- MobileIMSDK的核心库(此jar没有上传到mave中央库,请注意本地引用路径哦) -->
42   <dependency>
43     <groupId>com.x52im</groupId>
44     <artifactId>mobileimsdk-server</artifactId>
45     <version>6.5</version>
46     <scope>system</scope>
47     <systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/MobileIMSDKServer.jar</systemPath>
48   </dependency>
49  
50 </dependencies>

 以RainbowChat的Server工程为例,示例如下图:

2.3 引用lib包(Eclipse工程)

① Eclipse中如何引用第3方jar包?

跟所有Java工程一样引用jar包很简单,如果没试过,请查看:Eclipse中导入外部jar包 或 Eclipse下导入外部jar包的3种方式

② 以MobileIMSDK Server的Demo工程为例,结果如下图:

第二部分:编写代码

第1步:准备回调通知的实现类

① 框架基本事件回调实现类:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 与客服端的所有数据交互事件在此ServerEventListener子类中实现即可。
 * 
 * @author Jack Jiang
 * @version 1.0
 * @since 3.1
 */
public class ServerEventListenerImpl implements ServerEventListener
{
    private static Logger logger = LoggerFactory.getLogger(ServerEventListenerImpl.class);  
    
    /**
     * 用户身份验证回调方法定义(即验证客户端连接的合法性,合法就允许正常能信,否则断开).
     * <p>
     * 服务端的应用层可在本方法中实现用户登陆验证。
     * <br>
     * 注意:本回调在一种特殊情况下——即用户实际未退出登陆但再次发起来登陆包时,本回调是不会被调用的!
     * <p>
     * 根据MobileIMSDK的算法实现,本方法中用户验证通过(即方法返回值=0时)后
     * ,将立即调用回调方法 {@link #onUserLoginSucess(int, String, IoSession)}。
     * 否则会将验证结果(本方法返回值错误码通过客户端的 ChatBaseEvent.onLoginResponse(int userId, int errorCode)
     * 方法进行回调)通知客户端)。
     * 
     * @param userId 传递过来的准一id,保证唯一就可以通信,可能是登陆用户名、也可能是任意不重复的id等,具体意义由业务层决定
     * @param token 用于身份鉴别和合法性检查的token,它可能是登陆密码,也可能是通过前置单点登陆接口拿到的token等,具体意义由业务层决定
     * @param extra 额外信息字符串。本字段目前为保留字段,供上层应用自行放置需要的内容
     * @param session 此客户端连接对应的 netty “会话”
     * @return 0 表示登陆验证通过,否则可以返回用户自已定义的错误码,错误码值应为:>=1025的整数
     */
    @Override
    public int onUserLoginVerify(String userId, String token, String extra, Channel session)
    {
        logger.debug("【DEBUG_回调通知】正在调用回调方法:OnVerifyUserCallBack...(extra="+extra+")");
        return 0;
    }

    /**
     * 用户登录验证成功后的回调方法定义(在业务上可理解为该用户的上线通知).
     * <p>
     * 服务端的应用层通常可在本方法中实现用户上线通知等。
     * <br>
     * 注意:本回调在一种特殊情况下——即用户实际未退出登陆但再次发起来登陆包时,回调也是一定会被调用。
     * 
     * @param userId 传递过来的准一id,保证唯一就可以通信,可能是登陆用户名、也可能是任意不重复的id等,具体意义由业务层决定
     * @param extra 额外信息字符串。本字段目前为保留字段,供上层应用自行放置需要的内容。为了丰富应用层处理的手段,在本回调中也把此字段传进来了
     * @param session 此客户端连接对应的 netty “会话”
     */
    @Override
    public void onUserLoginSucess(String userId, String extra, Channel session)
    {
        logger.debug("【IM_回调通知onUserLoginSucess】用户:"+userId+" 上线了!");
    }

    /**
     * 用户退出登录回调方法定义(可理解为下线通知回调)。
     * <p>
     * 服务端的应用层通常可在本方法中实现用户下线通知等。
     * 
     * @param userId 下线的用户user_id
     * @param session 此客户端连接对应的 netty “会话”
     * @param beKickoutCode 被踢原因编码,本参数当为-1时表示本次logout事件不是源自“被踢”,否则被踢原因编码请见 {@link PKickoutInfo}类中的常量定义
     * @see {@link OnlineProcessor#setBeKickoutCodeForChannel(Channel, int)}
     */
    @Override
    public void onUserLogout(String userId, Channel session, int beKickoutCode)
    {
        logger.debug("【DEBUG_回调通知onUserLogout】用户:"+userId+" 离线了(beKickoutCode="+beKickoutCode+")!");
    }
    
    /**
     * 收到客户端发送给“服务端”的数据回调通知(即:消息路径为“C2S”的消息)前的处理逻辑。
     * <p>
     * <b>本方法的默认实现</b>:<font color="green">当开发者不需要本方法进行额外逻辑处理时,请直接返回true即可!</font>
     * <p>
     * <b>本方法的典型用途</b>:开发者可在本方法中实现如:用户聊天内容的鉴黄、过滤、篡改等等,把内容审读权限交给开发者,就看怎么用了。
     * 
     * @param p 消息/指令的完整协议包对象
     * @param session 消息发送者的“会话”引用(也就是客户端的网络连接对象)
     * @return true表示经过本方法后将正常进入 {@link #onTransferMessage4C2S(Protocal, Channel)}继续正常逻辑  ,false表示该条指令将不会继续处理(直接被丢弃)
     * @see #onTransferMessage4C2S(Protocal, Channel)
     * @since 6.2
     */
    @Override
    public boolean onTransferMessage4C2CBefore(Protocal p, Channel session)
    {
        return true;
    }
    
    /**
     * 收到客户端发送给“其它客户端”的数据回调通知(即:消息路径为“C2C”的消息)前的处理逻辑。
     * <p>
     * <b>本方法的默认实现</b>:<font color="green">当开发者不需要本方法进行额外逻辑处理时,请直接返回true即可!</font>
     * <p>
     * <b>本方法的典型用途</b>:开发者可在本方法中实现如:用户聊天内容的鉴黄、过滤、篡改等等,把内容审读权限交给开发者,就看怎么用了。
     * 
     * @param p 消息/指令的完整协议包对象
     * @param session 消息发送者的“会话”引用(也就是客户端的网络连接对象)
     * @return true表示经过本方法后将正常进入 {@link #onTransferMessage4C2C(Protocal)}继续正常逻辑  ,false表示该条指令将不会继续处理(直接被丢弃)
     * @see #onTransferMessage4C2C(Protocal)
     * @since 6.2
     */
    @Override
    public boolean onTransferMessage4C2SBefore(Protocal p, Channel session)
    {
        return true;
    }

    /**
     * 收到客户端发送给“服务端”的数据回调通知(即:消息路径为“C2S”的消息).
     * <p>
     * MobileIMSDK在收到客户端向userId="0"(即接收目标是"服务器")的情况下通过
     * 本方法的回调通知上层。
     * <p>
     * <b>本方法的典型用途</b>:开发者通常可在本方法中实现如:添加好友请求等需要服务端进行处理的业务。
     * 
     * @param p 消息/指令的完整协议包对象
     * @param session 此客户端连接对应的 netty “会话”
     * @return true表示本方法已成功处理完成,否则表示未处理成功。此返回值目前框架中并没有特殊意义,仅作保留吧
     * @see Protocal
     * @since 4.0
     */
    @Override
    public boolean onTransferMessage4C2S(Protocal p, Channel session)
    {
        // 接收者uid
        String userId = p.getTo();
        // 发送者uid
        String from_user_id = p.getFrom();
        // 消息或指令内容
        String dataContent = p.getDataContent();
        // 消息或指令指纹码(即唯一ID)
        String fingerPrint = p.getFp();
        // 【重要】用户定义的消息或指令协议类型(开发者可据此类型来区分具体的消息或指令)
        int typeu = p.getTypeu();
                
        logger.debug("【DEBUG_回调通知】[typeu="+typeu+"]收到了客户端"+from_user_id+"发给服务端的消息:str="+dataContent);
        return true;
    }

    /**
     * 收到客户端发送给“其它客户端”的数据回调通知(即:消息路径为“C2C”的消息).
     * <p>
     * <b>注意:</b>本方法当且仅当在数据被服务端成功实时发送(“实时”即意味着对方在线的情况下)出去后被回调调用.
     * <p>
     * <b>本方法的典型用途</b>:开发者可在本方法中可以实现用户聊天信息的收集,以便后期监控分析用户的行为等^_^。
     * 开发者可以对本方法不作任何代码实现,也不会影响整个MobileIMSDK的运行,因为本回调并非关键逻辑,只是个普通消息传输结果的回调而已。
     * <p>
     * 提示:如果开启消息QoS保证,因重传机制,本回调中的消息理论上有重复的可能,请以参数 #fingerPrint
     * 作为消息的唯一标识ID进行去重处理。
     * 
     * @param p 消息/指令的完整协议包对象
     * @see Protocal
     * @since 4.0
     */
    @Override
    public void onTransferMessage4C2C(Protocal p)
    {
        // 接收者uid
        String userId = p.getTo();
        // 发送者uid
        String from_user_id = p.getFrom();
        // 消息或指令内容
        String dataContent = p.getDataContent();
        // 消息或指令指纹码(即唯一ID)
        String fingerPrint = p.getFp();
        // 【重要】用户定义的消息或指令协议类型(开发者可据此类型来区分具体的消息或指令)
        int typeu = p.getTypeu();
                
        logger.debug("【DEBUG_回调通知】[typeu="+typeu+"]收到了客户端"+from_user_id+"发给客户端"+userId+"的消息:str="+dataContent);
    }

    /**
     * 服务端在进行消息发送时,当对方在线但实时发送失败、以及其它各种问题导致消息并没能正常发出时
     * ,将无条件走本回调通知。
     * 
     * <p>
     * <b>注意:</b>本方法当且仅当在数据被服务端<u>在线发送</u>失败后被回调调用.
     * 
     * <p>
     * <b>举个例子:以下是一段典型的服务端消息/指令发送代码:</b>
     * <pre style="border: 1px solid #eaeaea;background-color: #fff6ea;border-radius: 6px;">
     * // 消息接收者的id(这个id由你自已定义,对于MobileIMSDK来说只要保证唯一性即可)
     * String destinationUserId = "400069";
     * 
     * // 这是要发送的消息("你好"是消息内容、“0”是消息发送者)
     * final Protocal p = ProtocalFactory.createCommonData("你好", "0", destinationUserId, true, null, -1);
     *     
     * // 对方在线的情况下,才需要实时发送,否则走离线处理逻辑
     * if(OnlineProcessor.isOnline(destinationUserId)) {
     *     // netty是异步通知数据发送结果的
     *     MBObserver<Object> resultObserver = new MBObserver<Object>(){
     *         public void update(boolean sucess, Object extraObj) {
     *             if(sucess){
     *                 // 你的消息/指令实时发送成功,不需要额外处理了
     *             }
     *             else{
     *                 //【1】TODO: 你的消息/指令实时发送失败,在这里实现离线消息处理逻辑!
     *             }
     *         }
     *     };
     *         
     *     //【2】开始实时消息/指令的发送
     *     LocalSendHelper.sendData(p, resultObserver);
     * }
     * else{
     *     //【3】TODO: 你的离线消息处理逻辑!
     * }
     * <br>
     * <font color="#0000ff">如上代码所示:“【1】【3】”代码处,开发者可以自行明确地进行离线逻辑处理,“【2】”处如
     * 果实时发送时出现任何问题,将会走本回调方法进行通知,框架正是通过此回调进一步确保消息可靠性保证的。</font>
     * </pre>
     * <p>
     * 
     * <p>
     * <b>本方法的典型用途</b>:<br>
     * 开发者可在本方法中实现离线消息的持久化存储(反正进到本回调通知的消息,就是应该被离线存储起来的)。
     * 
     * <p>
     * <b>此方法存的意义何在?</b><br>
     * 发生此种情况的场景可能是:对方确实不在线(那么此方法里就可以作为离线消息处理了)、或者在发送时判断对方是在线的
     * 但服务端在发送时却没有成功(这种情况就可能是通信错误或对方非正常通出但尚未到达会话超时时限)。<br><u>应用层在
     * 此方法里实现离线消息的处理即可!</u>
     * 
     * @param p 消息/指令的完整协议包对象
     * @return true表示应用层已经处理了离线消息(如果该消息有QoS机制,则服务端将代为发送一条伪应答包
     * (伪应答仅意味着不是接收方的实时应答,而只是存储到离线DB中,但在发送方看来也算是被对方收到,只是延
     * 迟收到而已(离线消息嘛))),否则表示应用层没有处理(如果此消息有QoS机制,则发送方在QoS重传机制超时
     * 后报出消息发送失败的提示)
     * @see Protocal
     * @see #onTransferMessage4C2C(Protocal)
     * @since 4.0
     */
    @Override
    public boolean onTransferMessage_RealTimeSendFaild(Protocal p)
    {
        // 接收者uid
        String userId = p.getTo();
        // 发送者uid
        String from_user_id = p.getFrom();
        // 消息或指令内容
        String dataContent = p.getDataContent();
        // 消息或指令指纹码(即唯一ID)
        String fingerPrint = p.getFp();
        // 【重要】用户定义的消息或指令协议类型(开发者可据此类型来区分具体的消息或指令)
        int typeu = p.getTypeu();

        logger.debug("【DEBUG_回调通知】[typeu="+typeu+"]客户端"+from_user_id+"发给客户端"+userId+"的消息:str="+dataContent
                +",因实时发送没有成功,需要上层应用作离线处理哦,否则此消息将被丢弃.");
        return false;
    }


    /**
     * <b>注意:</b><font color="red">本回调仅用于与Web的互通模式下,默认情况下本方法可什么也不做,无任何影响。如你对此回调有疑问可跟Jack Jiang进行技术讨论!</font>
     * {@inheritDoc}
     * 
     * @since 6.2
     */
    @Override
    public void onTransferMessage4C2C_AfterBridge(Protocal p)
    {    
        // 默认本方法可
    }
}

② 服务端主动发起消息的QoS回调通知实现类:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * MobileIMSDK的服务端QoS消息送达保证机制的事件监听器实现类。
 * <p>
 * <b>当前QoS机制支持全部的C2C、C2S、S2C共3种消息交互场景下的消息送达质量保证:<</b>>
 * <ur>
 * <li>1) Client to Server(C2S):即由某客户端主动发起,消息最终接收者是服务端,此模式下:重发由C保证、ACK应答由S发回;</li>
 * <li>2) Server to Client(S2C):即由服务端主动发起,消息最终接收者是某客户端,此模式下:重发由S保证、ACK应答由C发回;</li>
 * <li>2) Client to Client(C2C):即由客户端主动发起,消息最终接收者是另一客户端。此模式对于QoS机制来说,相当于C2S+S2C两程路径。</li>
 * </ul>
 * <p>
 * TCP理论上能从底层保证数据的可靠性,但应用层的代码和场景中存在网络本身和网络之外的各种不可靠性,
 * MobileIMSDK中的QoS送达保证机制,将加强TCP的可靠性,确保消息,无法从哪一个层面和维度,都会给
 * 开发者提供两种结果:要么明确被送达(即收到ACK应答包,见 {@link #messagesBeReceived(String)})
 * 、要行明确未被送达(见 {@link #messagesLost(ArrayList)})。从理论上,保证消息的百分百送达率。
 * 
 * @author Jack Jiang
 * @version 1.0
 * @since 3.1
 * @see net.x52im.mobileimsdk.server.qos.QoS4SendDaemonS2C
 * @see net.x52im.mobileimsdk.server.qos.QoS4ReciveDaemonC2S
 * @see MessageQoSEventListenerS2C
 */
public class MessageQoSEventS2CListnerImpl implements MessageQoSEventListenerS2C
{
    private static Logger logger = LoggerFactory.getLogger(MessageQoSEventS2CListnerImpl.class);  
    
    /**
     * 消息未送达的回调事件通知.
     * 
     * @param lostMessages 由MobileIMSDK QoS算法判定出来的未送达消息列表(此列表
     * 中的Protocal对象是原对象的clone(即原对象的深拷贝),请放心使用哦),应用层
     * 可通过指纹特征码找到原消息并可以UI上将其标记为”发送失败“以便即时告之用户
     */
    @Override
    public void messagesLost(ArrayList<Protocal> lostMessages)
    {
        logger.debug("【DEBUG_QoS_S2C事件】收到系统的未实时送达事件通知,当前共有"
                        +lostMessages.size()+"个包QoS保证机制结束,判定为【无法实时送达】!");
    }

    /**
     * 消息已被对方收到的回调事件通知.
     * <p>
     * <b>目前,判定消息被对方收到是有两种可能:</b><br>
     * 1) 对方确实是在线并且实时收到了;<br>
     * 2) 对方不在线或者服务端转发过程中出错了,由服务端进行离线存储成功后的反馈
     * (此种情况严格来讲不能算是“已被收到”,但对于应用层来说,离线存储了的消息
     * 原则上就是已送达了的消息:因为用户下次登陆时肯定能通过HTTP协议取到)。
     * 
     * @param theFingerPrint 已被收到的消息的指纹特征码(唯一ID),应用层可据此ID
     * 来找到原先已发生的消息并可在UI是将其标记为”已送达“或”已读“以便提升用户体验
     */
    @Override
    public void messagesBeReceived(String theFingerPrint)
    {
        if(theFingerPrint != null)
        {
            logger.debug("【DEBUG_QoS_S2C事件】收到对方已收到消息事件的通知,fp="+theFingerPrint);
        }
    }
}

第2步:服务端最终配置和实现

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * IM服务的启动主类。
 * <p>
 * <b>友情提示:</b>其实MobileIMSDK的服务端并非只能以main的主类方式独立启动,你完全可以把它放到诸如java的Web工程里作为子模块运行,不会有任何问题!
 * 
 * @author Jack Jiang
 * @version 1.0*/
public class ServerLauncherImpl extends ServerLauncher
{
    private static Logger logger = LoggerFactory.getLogger(ServerLauncherImpl.class);  
    
    /**
     * 静态类方法:进行一些全局配置设置。
     */
    static
    {
        // 设置MobileIMSDK服务端的UDP网络监听端口
        GatewayUDP.PORT       = 7901;
        // 设置MobileIMSDK服务端的TCP网络监听端口
        GatewayTCP.PORT       = 8901;
        // 设置MobileIMSDK服务端的WebSocket网络监听端口
        GatewayWebsocket.PORT = 3000;
        
        // 设置MobileIMSDK服务端仅支持UDP协议
//        ServerLauncher.supportedGateways = Gateway.SOCKET_TYPE_UDP;
        // 设置MobileIMSDK服务端仅支持TCP协议
//        ServerLauncher.supportedGateways = Gateway.SOCKET_TYPE_TCP;
        // 设置MobileIMSDK服务端仅支持WebSocket协议
//        ServerLauncher.supportedGateways = Gateway.SOCKET_TYPE_WEBSOCKET;
        // 设置MobileIMSDK服务端同时支持UDP、TCP、WebSocket三种协议
        ServerLauncher.supportedGateways = Gateway.SOCKET_TYPE_UDP | Gateway.SOCKET_TYPE_TCP | Gateway.SOCKET_TYPE_WEBSOCKET;
        
        // 开/关Demog日志的输出
        QoS4SendDaemonS2C.getInstance().setDebugable(true);
        QoS4ReciveDaemonC2S.getInstance().setDebugable(true);
        
        // 与客户端协商一致的心跳频率模式设置
//        ServerToolKits.setSenseModeUDP(SenseModeUDP.MODE_15S);
        ServerToolKits.setSenseModeTCP(SenseModeTCP.MODE_5S);
        ServerToolKits.setSenseModeWebsocket(SenseModeWebsocket.MODE_5S);
//        ServerToolKits.setSenseModeWebsocket(SenseModeWebsocket.MODE_30S);

        // 关闭与Web端的消息互通桥接器(其实SDK中默认就是false)
        ServerLauncher.bridgeEnabled = false;
        // TODO 跨服桥接器MQ的URI(本参数只在ServerLauncher.bridgeEnabled为true时有意义)
//        BridgeProcessor.IMMQ_URI = "amqp://js:19844713@192.168.0.190";
        
        // 设置最大TCP帧内容长度(不设置则默认最大是 6 * 1024字节)
//        GatewayTCP.TCP_FRAME_MAX_BODY_LENGTH = 60 * 1024;
        
        SslContext sslContext = createSslContext();
        // 开启TCP协议的SSL/TLS加密传输(请确保客户端也已开发SSL)
//        GatewayTCP.sslContext = sslContext;
        // 开启WebSocket协议的SSL/TLS加密传输(请确保SSL证书是正规CA签发,否则浏览器是不允许的)
//        GatewayWebsocket.sslContext = sslContext;
    }
    
    /**
     * 实例构造方法。
     * 
     * @throws IOException
     */
    public ServerLauncherImpl() throws IOException
    {
        super();
    }
    
    /**
     * 初始化消息处理事件监听者.
     */
    @Override
    protected void initListeners()
    {
        // ** 设置各种回调事件处理实现类
        this.setServerEventListener(new ServerEventListenerImpl());
        this.setServerMessageQoSEventListener(new MessageQoSEventS2CListnerImpl());
    }
    
    /**
     * 创建SslContext对象,用于开启SSL/TLS加密传输。
     * 
     * @return 如果成功创建则返回SslContext对象,否则返回null
     */
    private static SslContext createSslContext()
    {        
        try {
            /** 示例 1:使用证书(证书位于绝对路径)*/
//            // 证书文件
//            File certChainFile = new File("c:/certs/netty-cert2.crt");
//            // 证书文件
//            File keyFile = new File("c:/certs/netty-key2.pk8");
//            // 私钥密码(注意:Netty只支持.pk8格式,如何生成,见JackJiang文章:)
//            String keyPassword = "123456";
//            // 生成SslContext对象(为了方便理解,此处使用的是单向认证)
//            SslContext sslCtx = SslContextBuilder.forServer(certChainFile, keyFile, keyPassword).clientAuth(ClientAuth.NONE).build();
                
            /** 示例 2:使用证书(证书位于相对路径)*/
            // TODO: 注意:请使用自已的证书,Demo中带的证书为自签名证书且已绑定域名,不安全!!!
            // 证书文件
            InputStream certChainFile = ServerLauncherImpl.class.getResourceAsStream("certs/netty-cert2.crt");
            // 私钥文件(注意:Netty只支持.pk8格式,如何生成,见JackJiang文章:)
            InputStream keyFile = ServerLauncherImpl.class.getResourceAsStream("certs/netty-key2.pk8");
            // 私钥密码(注意:Netty只支持.pk8格式,如何生成,见JackJiang文章:)
            String keyPassword = "123456";
            // 生成SslContext对象(为了方便理解,此处使用的是单向认证)
            SslContext sslCtx = SslContextBuilder.forServer(certChainFile, keyFile, keyPassword).clientAuth(ClientAuth.NONE).build();
                
            /** 示例 3:使用Netty自带的自签名证书(建议该证书仅用于测试使用)*/
//            SelfSignedCertificate ssc = new SelfSignedCertificate();
//            SslContext sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
                
            return sslCtx;
        } catch (Exception e) {
             logger.warn("createSslContext()时出错了,原因:"+e.getMessage(), e);
        }
        
        return null;
    }
    
    /**
     * Demo程序主入口函数。
     * 
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception 
    {
        // 实例化后记得startup哦,单独startup()的目的是让调用者可以延迟决定何时真正启动IM服务
        final ServerLauncherImpl sli = new ServerLauncherImpl();
        
        // 启动MobileIMSDK服务端的Demo
        sli.startup();
        
        // 加一个钩子,确保在JVM退出时释放netty的资源
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                sli.shutdown();
            }
        });
    }
}

第三部分:常见开发问题附录

附录1:可以让客户端更省电吗?

为了配合AndroidiOS客户端,Server端也需要进行设置。

请调用以下API进行设置即可(框架默认工作在SenseMode.MODE_15S模式下):

// MobileIMSDK核心IM框架的服务端敏感度模式设置 ServerLauncherImpl.setSenseMode(SenseMode.MODE_15S);

MobileIMSDK预定义了多种模式,详细API说明:点此进入

特别说明:为了保证算法的一致性,以上设置需所有平台客户端和服务端都保持一致,否则将发生不可预测问题。

附录2:服务端如何向客户端推送/发送数据(或消息)?

服务端使用 LocalSendHelper 类中的sendData系列方法即可,详见下图:

API文档在线地址:http://docs.52im.net/extend/docs/api/mobileimsdk/server_tcp/

附录3:核心库工程与Demo演示工程的关系说明

如下图所示:从 Github 或 淘宝 得到的核心库工程和Demo演示工程

(▲ 左边为MobileIMSDK的各平台核心库工程,右边为各平台的Demo演示工程)

* 什么是核心库工程?

核心库工程就是MobileIMSDK的所有框架源码,它只是个lib库,它的作用就像Spring boot、Struts、log4j这些第3库lib库一样:是打成jar包放到您的工程里使用的,您调用它就能实现它提供的功能,它自已本身并不能自已运行(你不可能让log4j或Spring boot能双击就运行吧?)

* 什么是Demo演示工程?

正如“什么是核心库工程?”一节所说,MobileIMSDK的核心库是不能直接运行的,它需要打成jar包被您的工程引用并调用后,才能发挥它的作用,所以MobileIMSDK的Demo演示工程的目的就是为了告诉你:如何引用MobileIMSDK的核心库jar包、如何调用MobileIMSDK的API,读Demo代码就知道如何使用它了(所以Demo代码唯一的意义就是为您演示库的调用,别无他用)!

* “我”的工程中使用使用核心库工程?

为了方便日后的升级,建议使用MobileIMSDK编译好的核心库jar包,当然您也可以直接把MobileIMSDK核心库源库放到您的工程中(而不是使用编译好的jar包)。

* 您可以在MobileIMSDK的Github如下目录中找到打包编译好的jar包:

附录4:如何开启SSL/TLS传输加密

1 您需要准备一个SSL/TLS证书(支持自签名证书)

可以使用正规CA机构签发的证书,也可以使用自签名证书,如何生成自签名证书可自行百度,这方面资料很丰富。

证书文件就像这样:

注:如果你不想买证书,也不知道如何生成自签名证书,可以跟着这篇文章自已做《手把手教你为基于Netty的IM生成自签名SSL/TLS证书》。

2 代码中启用SSL/TLS加密

* 将准备好的证书放置到服务端工程的此目录下(以MobileIMSDK的服务端Demo工程为例):

* 启用SSL/TLS配置(取消此行代码注释即可):

* 启用SSL/TLS后的运行效果(服务端控制台log中出现此字样即表示SSL/TLS启用成功!):

(▲ 服务端启动时控制台下关于已开启TLS/SSL加密的log输出(run.bat运行时))

(▲ 服务端启动时控制台下关于已开启TLS/SSL加密的log输出(IDEA中运行时))

(▲ 客户端发起WebSocket连接时,服务端控制台下带有TLS/SSL信息的握手log)(内容参考自:http://www.52im.net/thread-63-1-1.html)

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
SpringBoot集成开源IM框架MobileIMSDK,实现即时通讯IM聊天功能
MobileIMSDK  是一套专门为移动端开发的开源IM即时通讯框架,超轻量级、高度提炼,一套API优雅支持UDP 、TCP 、WebSocket 三种协议,支持iOS、Android、H5、标准Java平台,服务端基于Netty编写。
JackJiang
2022/05/05
3.3K0
SpringBoot集成开源IM框架MobileIMSDK,实现即时通讯IM聊天功能
开源即时通讯IM框架MobileIMSDK的鸿蒙NEXT端开发快速入门
小提示:鸿蒙Next中的WebSocket API跟标准HTML5中的WebSocket接口及用法略有不同,但主要API都能一一对应,相差不大。
JackJiang
2024/12/30
1910
开源即时通讯IM框架MobileIMSDK的鸿蒙NEXT端开发快速入门
基于开源IM即时通讯框架MobileIMSDK:RainbowChat v8.3版已发布
MobileIMSDK 是一套专门为移动端开发的开源IM即时通讯框架,超轻量级、高度提炼,一套API优雅支持UDP 、TCP 、WebSocket 三种协议,支持iOS、Android、H5、标准Java平台,服务端基于Netty编写。
JackJiang
2022/12/07
5890
基于开源IM即时通讯框架MobileIMSDK:RainbowChat v8.3版已发布
开源即时通讯IM框架MobileIMSDK的Uniapp端开发快速入门
(JackJiang 使用的版本号如下图所示,为了方便直接引用工程,建议你也使用此版或较新版本)
JackJiang
2023/05/18
6690
开源即时通讯IM框架MobileIMSDK的Uniapp端开发快速入门
开源即时通讯IM框架MobileIMSDK的H5端开发快速入门
如下图所示:所有 SDK 接口均由/mobileimsdk/mobileimsdk-client-sdk.js 提供。,接口设计跟MobileIMSDK 的APP版一样,均为高内聚和低侵入的回调方式传入SDK处理逻辑,无需(也不建议)开发者直接修改sdk级代码。
JackJiang
2023/06/15
4970
开源即时通讯IM框架MobileIMSDK的H5端开发快速入门
开源即时通讯IM框架MobileIMSDK的微信小程序端开发快速入门
**小提示:**微信小程序中的WebSocket API跟标准HTML5中的WebSocket接口及用法略有不同,但主要API都能一一对应,相差不大。
JackJiang
2023/04/07
1.7K0
开源即时通讯IM框架MobileIMSDK的微信小程序端开发快速入门
开源轻量级 IM 框架 MobileIMSDK 的微信小程序端已发布!
MobileIMSDK - 微信小程序端是一套基于微信原生 WebSocket 的即时通讯库:
JackJiang
2023/04/03
7970
开源轻量级 IM 框架 MobileIMSDK 的微信小程序端已发布!
开源移动端IM框架MobileIMSDK:快速入门
MobileIMSDK工程始于2013年10月,起初用作某产品的即时通讯底层实现,完全从零开发。
JackJiang
2018/08/23
2.7K0
开源移动端IM框架MobileIMSDK:快速入门
开源即时通讯IM框架 MobileIMSDK v6.5 发布
本次更新为次要版本更新,进行了bug修复和优化升级(更新历史详见:码云 Release Notes、Github Release Notes)。
JackJiang
2024/05/09
4580
开源即时通讯IM框架 MobileIMSDK v6.5 发布
基于开源IM即时通讯框架MobileIMSDK:RainbowChat v8.4版已发布
MobileIMSDK 是一套专门为移动端开发的开源IM即时通讯框架,超轻量级、高度提炼,一套API优雅支持UDP 、TCP 、WebSocket 三种协议,支持iOS、Android、H5、标准Java平台,服务端基于Netty编写。
JackJiang
2023/02/16
5040
基于开源IM即时通讯框架MobileIMSDK:RainbowChat v8.4版已发布
开源轻量级 IM 框架 MobileIMSDK 的Uniapp客户端库已发布
MobileIMSDK-Uniapp端是一套基于Uniapp跨端框架的即时通讯库:
JackJiang
2023/05/12
8921
开源轻量级 IM 框架 MobileIMSDK 的Uniapp客户端库已发布
WebSocket+Netty 1:1仿微信的即时通讯工具
技术基础之前都有写过了,直通车看下面连接 后端:WebSocket+Netty+SpringBoot+SpringMVC+SpringData+Mysql 中间件以及第三方服务:RabbitMQ+Redis+阿里云短信+OSS对象存储系统+Nginx Netty简单介绍以及它的模型基础 websocket的定位以及其和其他连接的区别 Netty+Websocket的群发即使通讯demo 前端: html5+vue+一些UI,链接可以看我之前的前端专题. 专门学了一下vue基础...以后没事了再多学点,以后自己做小玩具方便.
名字是乱打的
2021/12/24
9220
WebSocket+Netty 1:1仿微信的即时通讯工具
开源IM聊天程序HarmonyChat:基于鸿蒙NEXT的WebSocket协议
HarmonyChat是一个简洁的鸿蒙NEXT上的基于WebSocket协议的聊天客户端 ,它基于MobileIMSDK通信库, 有完善的网络通信通力、简洁的聊天界面UI、合理的代码拆分和逻辑实现,非常适合学习研究或直接用于简单的鸿蒙NEXT单页聊天项目中 。
JackJiang
2025/01/02
1950
开源IM聊天程序HarmonyChat:基于鸿蒙NEXT的WebSocket协议
开源即时通讯IM框架 MobileIMSDK v6.3 发布
本次更新为次要版本更新,进行了若干优化(更新历史详见:码云 Release Nodes)。可能是市面上唯一同时支持 UDP+TCP+WebSocket 三种协议的同类开源IM框架。
JackJiang
2023/02/08
1.4K0
开源即时通讯IM框架 MobileIMSDK v6.3 发布
基于开源IM即时通讯框架MobileIMSDK:RainbowChat-iOS端v6.1版已发布
MobileIMSDK 是一套专门为移动端开发的开源IM即时通讯框架,超轻量级、高度提炼,一套API优雅支持UDP 、TCP 、WebSocket 三种协议,支持iOS、Android、H5、标准Java平台,服务端基于Netty编写。
JackJiang
2022/11/05
8520
基于开源IM即时通讯框架MobileIMSDK:RainbowChat-iOS端v6.1版已发布
开源即时通讯IM框架 MobileIMSDK v6.2 发布
本次更新为次要版本更新,进行了若干优化(更新历史详见:码云 Release Nodes)。可能是市面上唯一同时支持 UDP+TCP+WebSocket 三种协议的同类开源IM框架。
JackJiang
2022/07/19
1.5K0
开源即时通讯IM框架 MobileIMSDK v6.2 发布
【Netty】Netty+springboot实现IM即时通讯服务端
按照处理方式的不同 可以分为操作类别 (操作用户 操作群组等) 消息类别 (一对一 一对多)
冷环渊
2022/04/28
2K0
【Netty】Netty+springboot实现IM即时通讯服务端
为自己搭建一个分布式 IM(即时通讯) 系统
之前分享过一篇《设计一个百万级的消息推送系统》;虽然我在文中有贴一些伪代码,依然有些朋友希望能直接分享一些可以运行的源码;这么久了是时候把坑填上了。
java进阶架构师
2019/03/01
2.6K0
为自己搭建一个分布式 IM(即时通讯) 系统
开源轻量级 IM 框架 MobileIMSDK v6.1.2 发布!
本次更新为次要版本更新,进行了若干优化(更新历史详见:码云 Release Nodes)。可能是市面上唯一同时支持 UDP+TCP+WebSocket 三种协议的同类开源IM框架。
JackJiang
2021/12/16
1.3K0
开源轻量级 IM 框架 MobileIMSDK v6.1.2 发布!
NIO框架入门(二):服务端基于MINA2的UDP双向通信Demo演示
NIO框架的流行,使得开发大并发、高性能的互联网服务端成为可能。这其中最流行的无非就是MINA和Netty了,MINA目前的主要版本是MINA2、而Netty的主要版本是Netty3和Netty4(Netty5已经被取消开发了:详见此文)。
JackJiang
2018/08/23
8930
NIO框架入门(二):服务端基于MINA2的UDP双向通信Demo演示
推荐阅读
相关推荐
SpringBoot集成开源IM框架MobileIMSDK,实现即时通讯IM聊天功能
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验