SpringBoot整合開源IM框架MobileIMSDK,實現即時通訊IM聊天功能

JackJiang發表於2022-05-05

一、前言

MobileIMSDK 是什麼?

MobileIMSDK 是一套專門為移動端開發的開源IM即時通訊框架,超輕量級、高度提煉,一套API優雅支援UDP 、TCP 、WebSocket 三種協議,支援iOS、Android、H5、標準Java平臺,服務端基於Netty編寫。

工程地址是:

1)Gitee碼雲地址:https://www.oschina.net/p/mob...
2)Github託管地址:https://github.com/JackJiang2...

本文將實現:

1)基於springboot 整合 MobileIMSDK;
2)開發IM服務端;
3)開發客戶端;
4)實現Java客戶端與客戶端之間的通訊。

  • 補充說明:本文所示Demo原始碼,請從文末“本文小結”的最後連結中下載!

二、SpringBoot 整合 MobileIMSDK 準備

2.1 MobileIMSDK下載
MobileIMSDK下載地址:

1)國外地址:MobileIMSDK的Github地址(最新版打包下載)
2)國內地址:MobileIMSDK的碼雲gitee地址(訪問速度快!,最新版打包下載)

需要用到的lib包:

1)服務端所需jar包: sdk_binary/Server/
2)客服端所需jar包: sdk_binary/Client_TCP/java/

如下圖所示:

2.2 pom.xml中引入相關依賴
由於這裡是maven專案,其中一部分jar包可通過maven倉庫直接引入,而其餘的則通過外部jar包引入方式使用即可~

如下4個需作為外部jar包在pom.xml中引入 :
<!-- [url=https://mvnrepository.com/art...]https://mvnrepository.com/artifact/com.google.code.gson/gson[/url] -->
<dependency>

<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>

</dependency>

<!-- MobileIMSDK所需jar包依賴[注:這裡是在本地lib中引入,maven中央倉庫中暫無此jar包],要與<includeSystemScope>true</includeSystemScope>配合使用-->

<dependency>

<groupId>com.zhengqing</groupId>

<artifactId>MobileIMSDK4j</artifactId>

<scope>system</scope>

<systemPath>${project.basedir}/src/main/resources/lib/MobileIMSDK4j.jar</systemPath>

</dependency>

<dependency>

<groupId>com.zhengqing</groupId>

<artifactId>MobileIMSDKServerX_meta</artifactId>

<scope>system</scope>

<systemPath>${project.basedir}/src/main/resources/lib/MobileIMSDKServerX_meta.jar</systemPath>

</dependency>

<dependency>

<groupId>com.zhengqing</groupId>

<artifactId>swing-worker-1.2(1.6-)</artifactId>

<scope>system</scope>

<systemPath>${project.basedir}/src/main/resources/lib/swing-worker-1.2(1.6-).jar</systemPath>

</dependency>

<dependency>

<groupId>com.zhengqing</groupId>

<artifactId>MobileIMSDKServerX_netty</artifactId>

<scope>system</scope>

<systemPath>${project.basedir}/src/main/resources/lib/MobileIMSDKServerX_netty.jar</systemPath>

</dependency>

<plugins>

<!-- maven打包外掛 -> 將整個工程打成一個 fatjar -->

<plugin>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-maven-plugin</artifactId>

    <!-- 作用:專案打成jar,同時把本地jar包也引入進去 -->

    <configuration>

        <includeSystemScope>true</includeSystemScope>

    </configuration>

</plugin>

</plugins>

三、開發服務端

3.1 與客服端的所有資料互動事件(實現ServerEventListener類)

public class ServerEventListenerImpl implements ServerEventListener {
    private static Logger logger = LoggerFactory.getLogger(ServerEventListenerImpl.class);
 
    /**
     * 使用者身份驗證回撥方法定義.
     * <p>
     * 服務端的應用層可在本方法中實現使用者登陸驗證。
     * <br>
     * 注意:本回撥在一種特殊情況下——即使用者實際未退出登陸但再次發起來登陸包時,本回撥是不會被呼叫的!
     * <p>
     * 根據MobileIMSDK的演算法實現,本方法中使用者驗證通過(即方法返回值=0時)後
     * ,將立即呼叫回撥方法 {@link #onUserLoginAction_CallBack(int, String, IoSession)}。
     * 否則會將驗證結果(本方法返回值錯誤碼通過客戶端的 ChatBaseEvent.onLoginMessage(int dwUserId, int dwErrorCode)
     * 方法進行回撥)通知客戶端)。
     *
     * @param userId  傳遞過來的準一id,保證唯一就可以通訊,可能是登陸使用者名稱、也可能是任意不重複的id等,具體意義由業務層決定
     * @param token   用於身份鑑別和合法性檢查的token,它可能是登陸密碼,也可能是通過前置單點登陸介面拿到的token等,具體意義由業務層決定
     * @param extra   額外資訊字串。本欄位目前為保留欄位,供上層應用自行放置需要的內容
     * @param session 此客戶端連線對應的 netty “會話”
     * @return 0 表示登陸驗證通過,否則可以返回使用者自已定義的錯誤碼,錯誤碼值應為:>=1025的整數
     */
    @Override
    public int onVerifyUserCallBack(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 onUserLoginAction_CallBack(String userId, String extra, Channel session) {
        logger.debug("【IM_回撥通知OnUserLoginAction_CallBack】使用者:"+ userId + " 上線了!");
    }
 
    /**
     * 使用者退出登入回撥方法定義(可理解為下線通知回撥)。
     * <p>
     * 服務端的應用層通常可在本方法中實現使用者下線通知等。
     *
     * @param userId  下線的使用者user_id
     * @param obj
     * @param session 此客戶端連線對應的 netty “會話”
     */
    @Override
    public void onUserLogoutAction_CallBack(String userId, Object obj, Channel session) {
        logger.debug("【DEBUG_回撥通知OnUserLogoutAction_CallBack】使用者:"+ userId + " 離線了!");
    }
 
    /**
     * 通用資料回撥方法定義(客戶端發給服務端的(即接收user_id="0")).
     * <p>
     * MobileIMSDK在收到客戶端向user_id=0(即接收目標是伺服器)的情況下通過
     * 本方法的回撥通知上層。上層通常可在本方法中實現如:新增好友請求等業務實現。
     *
     * <p style="background:#fbf5ee;border-radius:4px;">
     * <b><font color="#ff0000">【版本相容性說明】</font></b>本方法用於替代v3.x中的以下方法:<br>
     * <code>public boolean onTransBuffer_CallBack(String userId, String from_user_id
     * , String dataContent, String fingerPrint, int typeu, Channel session);
     * </code>
     *
     * @param userId       接收方的user_id(本方法接收的是發給服務端的訊息,所以此引數的值肯定==0)
     * @param from_user_id 傳送方的user_id
     * @param dataContent  資料內容(文字形式)
     * @param session      此客戶端連線對應的 netty “會話”
     * @return true表示本方法已成功處理完成,否則表示未處理成功。此返回值目前框架中並沒有特殊意義,僅作保留吧
     * @since 4.0
     */
    @Override
    public boolean onTransBuffer_C2S_CallBack(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();
        // 【重要】使用者定義的訊息或指令協議型別(開發者可據此型別來區分具體的訊息或指令)
        inttypeu = p.getTypeu();
 
        logger.debug("【DEBUG_回撥通知】[typeu="+ typeu + "]收到了客戶端"+ from_user_id + "發給服務端的訊息:str="+ dataContent);
        returntrue;
    }
 
    /**
     * 通道資料回撥函式定義(客戶端發給客戶端的(即接收方user_id不為“0”的情況)).
     * <p>
     * <b>注意:</b>本方法當且僅當在資料被服務端成功線上傳送出去後被回撥呼叫.
     * <p>
     * 上層通常可在本方法中實現使用者聊天資訊的收集,以便後期監控分析使用者的行為等^_^。
     * <p>
     * 提示:如果開啟訊息QoS保證,因重傳機制,本回撥中的訊息理論上有重複的可能,請以引數 #fingerPrint
     * 作為訊息的唯一標識ID進行去重處理。
     *
     * <p style="background:#fbf5ee;border-radius:4px;">
     * <b><font color="#ff0000">【版本相容性說明】</font></b>本方法用於替代v3.x中的以下方法:<br>
     * <code>public void onTransBuffer_C2C_CallBack(String userId, String from_user_id
     * , String dataContent, String fingerPrint, int typeu);
     *
     * @param userId       接收方的user_id(本方法接收的是客戶端發給客戶端的,所以此引數的值肯定>0)
     * @param from_user_id 傳送方的user_id
     * @param dataContent
     * @since 4.0
     */
    @Override
    public void onTransBuffer_C2C_CallBack(Protocal p) {
        // 接收者uid
        String userId = p.getTo();
        // 傳送者uid
        String from_user_id = p.getFrom();
        // 訊息或指令內容
        String dataContent = p.getDataContent();
        // 訊息或指令指紋碼(即唯一ID)
        String fingerPrint = p.getFp();
        // 【重要】使用者定義的訊息或指令協議型別(開發者可據此型別來區分具體的訊息或指令)
        inttypeu = p.getTypeu();
 
        logger.debug("【DEBUG_回撥通知】[typeu="+ typeu + "]收到了客戶端"+ from_user_id + "發給客戶端"+ userId + "的訊息:str="+ dataContent);
    }
 
    /**
     * 通用資料實時傳送失敗後的回撥函式定義(客戶端發給客戶端的(即接收方user_id不為“0”的情況)).
     * <p>
     * 注意:本方法當且僅當在資料被服務端<u>線上傳送</u>失敗後被回撥呼叫.
     * <p>
     * <b>此方法存的意義何在?</b><br>
     * 發生此種情況的場景可能是:對方確實不線上(那麼此方法裡就可以作為離線訊息處理了)、
     * 或者在傳送時判斷對方是線上的但服務端在傳送時卻沒有成功(這種情況就可能是通訊錯誤
     * 或對方非正常通出但尚未到達會話超時時限)。<br><u>應用層在此方法裡實現離線訊息的處理即可!</u>
     *
     * <p style="background:#fbf5ee;border-radius:4px;">
     * <b><font color="#ff0000">【版本相容性說明】</font></b>本方法用於替代v3.x中的以下方法:<br>
     * <code>public boolean onTransBuffer_C2C_RealTimeSendFaild_CallBack(String userId
     * , String from_user_id, String dataContent, String fingerPrint, int typeu);
     * </code>
     *
     * @param userId       接收方的user_id(本方法接收的是客戶端發給客戶端的,所以此引數的值肯定>0),此id在本方法中不一定保證有意義
     * @param from_user_id 傳送方的user_id
     * @param dataContent  訊息內容
     * @param fingerPrint  該訊息對應的指紋(如果該訊息有QoS保證機制的話),用於在QoS重要機制下服務端離線儲存時防止重複儲存哦
     * @return true表示應用層已經處理了離線訊息(如果該訊息有QoS機制,則服務端將代為傳送一條偽應答包
     * (偽應答僅意味著不是接收方的實時應答,而只是儲存到離線DB中,但在傳送方看來也算是被對方收到,只是延
     * 遲收到而已(離線訊息嘛))),否則表示應用層沒有處理(如果此訊息有QoS機制,則傳送方在QoS重傳機制超時
     * 後報出訊息傳送失敗的提示)
     * @see #onTransBuffer_C2C_CallBack(Protocal)
     * @since 4.0
     */
    @Override
    public boolean onTransBuffer_C2C_RealTimeSendFaild_CallBack(Protocal p) {
        // 接收者uid
        String userId = p.getTo();
        // 傳送者uid
        String from_user_id = p.getFrom();
        // 訊息或指令內容
        String dataContent = p.getDataContent();
        // 訊息或指令指紋碼(即唯一ID)
        String fingerPrint = p.getFp();
        // 【重要】使用者定義的訊息或指令協議型別(開發者可據此型別來區分具體的訊息或指令)
        inttypeu = p.getTypeu();
 
        logger.debug("【DEBUG_回撥通知】[typeu="+ typeu + "]客戶端"+ from_user_id + "發給客戶端"+ userId + "的訊息:str="+ dataContent
                + ",因實時傳送沒有成功,需要上層應用作離線處理哦,否則此訊息將被丟棄.");
        returnfalse;
    }
}

3.2 服務端主動發起訊息的QoS回撥通知(實現MessageQoSEventListenerS2C類)
public class MessageQoSEventS2CListnerImpl implements MessageQoSEventListenerS2C {

private static Logger logger = LoggerFactory.getLogger(MessageQoSEventS2CListnerImpl.class);



@Override

public void messagesLost(ArrayList<Protocal> lostMessages) {

    logger.debug("【DEBUG_QoS_S2C事件】收到系統的未實時送達事件通知,當前共有"

            + lostMessages.size() + "個包QoS保證機制結束,判定為【無法實時送達】!");

}



@Override

public void messagesBeReceived(String theFingerPrint) {

    if(theFingerPrint != null) {

        logger.debug("【DEBUG_QoS_S2C事件】收到對方已收到訊息事件的通知,fp="+ theFingerPrint);

    }

}

}

3.3 服務端配置
public class ServerLauncherImpl extends ServerLauncher {

// 靜態類方法:進行一些全域性配置設定

static{

    // 設定MobileIMSDK服務端的網路監聽埠

    ServerLauncherImpl.PORT = 7901;



    // 開/關Demog日誌的輸出

    QoS4SendDaemonS2C.getInstance().setDebugable(true);

    QoS4ReciveDaemonC2S.getInstance().setDebugable(true);

    ServerLauncher.debug = true;



    // TODO 與客戶端協商一致的心跳敏感模式設定

// ServerToolKits.setSenseMode(SenseMode.MODE_10S);

    // 關閉與Web端的訊息互通橋接器(其實SDK中預設就是false)

    ServerLauncher.bridgeEnabled = false;

    // TODO 跨服橋接器MQ的URI(本引數只在ServerLauncher.bridgeEnabled為true時有意義)

// BridgeProcessor.IMMQ_URI = "amqp://js:19844713@192.168.31.190";

}



// 例項構造方法

public ServerLauncherImpl() throws IOException {

    super();

}



/**

 * 初始化訊息處理事件監聽者.

 */

@Override

protected void initListeners() {

    // ** 設定各種回撥事件處理實現類

    this.setServerEventListener(newServerEventListenerImpl());

    this.setServerMessageQoSEventListener(newMessageQoSEventS2CListnerImpl());

}

}

3.4 服務端啟動類
溫馨小提示:這裡由於小編將服務端和客戶端整合在同一個專案中,因此如下配置:

SpringBoot的CommandLineRunner介面主要用於實現在服務初始化後,去執行一段程式碼塊邏輯(run方法),這段初始化程式碼在整個應用生命週期內只會執行一次!
@Order(value = 1) :按照一定的順序去執行,value值越小越先執行
@Slf4j

@Component

@Order(value = 1)

public class ChatServerRunner implements CommandLineRunner {

@Override

public void run(String... strings) throws Exception {

    log.info("================= ↓↓↓↓↓↓ 啟動MobileIMSDK服務端 ↓↓↓↓↓↓ =================");

    // 例項化後記得startup哦,單獨startup()的目的是讓呼叫者可以延遲決定何時真正啟動IM服務

    final ServerLauncherImpl sli = new ServerLauncherImpl();

    // 啟動MobileIMSDK服務端的Demo

    sli.startup();



    // 加一個鉤子,確保在JVM退出時釋放netty的資源

    Runtime.getRuntime().addShutdownHook(newThread(sli::shutdown));

}

}

如果服務端與客戶端不在同一個專案 ,服務端可直接通過如下方式啟動即可~

四、開發客戶端

4.1 客戶端與IM服務端連線事件
@Slf4j

public class ChatBaseEventImpl implements ChatBaseEvent {

@Override

public void onLoginMessage(int dwErrorCode) {

    if(dwErrorCode == 0) {

        log.debug("IM伺服器登入/連線成功!");

    } else{

        log.error("IM伺服器登入/連線失敗,錯誤程式碼:"+ dwErrorCode);

    }

}



@Override

public void onLinkCloseMessage(int dwErrorCode) {

    log.error("與IM伺服器的網路連線出錯關閉了,error:"+ dwErrorCode);

}

}

4.2 接收訊息事件
@Slf4j

public class ChatTransDataEventImpl implements ChatTransDataEvent {

@Override

public void onTransBuffer(String fingerPrintOfProtocal, String userid, String dataContent, inttypeu) {

    log.debug("[typeu="+ typeu + "]收到來自使用者"+ userid + "的訊息:"+ dataContent);

}



@Override

public void onErrorResponse(int errorCode, String errorMsg) {

    log.debug("收到服務端錯誤訊息,errorCode="+ errorCode + ", errorMsg="+ errorMsg);

}

}

4.3 訊息是否送達事件
@Slf4j

public class MessageQoSEventImpl implements MessageQoSEvent {

@Override// 對方未成功接收訊息的回撥事件 lostMessages:存放訊息內容

public void messagesLost(ArrayList<Protocal> lostMessages) {

    log.debug("收到系統的未實時送達事件通知,當前共有"+ lostMessages.size() + "個包QoS保證機制結束,判定為【無法實時送達】!");

}



@Override// 對方成功接收到訊息的回撥事件

public void messagesBeReceived(String theFingerPrint) {

    if(theFingerPrint != null) {

        log.debug("收到對方已收到訊息事件的通知,fp="+ theFingerPrint);

    }

}

}

4.4 MobileIMSDK初始化配置
public class IMClientManager {

private static IMClientManager instance = null;



/**

 * MobileIMSDK是否已被初始化. true表示已初化完成,否則未初始化.

 */

privatebooleaninit = false;



public static IMClientManager getInstance() {

    if(instance == null) {

        instance = new IMClientManager();

    }

    return instance;

}



private IMClientManager() {

    initMobileIMSDK();

}



public void initMobileIMSDK() {

    if(!init) {

        // 設定伺服器ip和伺服器埠

        ConfigEntity.serverIP = "127.0.0.1";

        ConfigEntity.serverPort = 8901;



        // MobileIMSDK核心IM框架的敏感度模式設定

// ConfigEntity.setSenseMode(SenseMode.MODE_10S);

        // 開啟/關閉DEBUG資訊輸出

        ClientCoreSDK.DEBUG = false;



        // 設定事件回撥

        ClientCoreSDK.getInstance().setChatBaseEvent(newChatBaseEventImpl());

        ClientCoreSDK.getInstance().setChatTransDataEvent(newChatTransDataEventImpl());

        ClientCoreSDK.getInstance().setMessageQoSEvent(newMessageQoSEventImpl());



        init = true;

    }

}

}

4.5 連線IM服務端,傳送訊息
服務類:

public interface IChatService {

/**

 * 登入連線IM伺服器請求

 *

 * @param username: 使用者名稱

 * @param password: 密碼

 * @return: void

 */

void loginConnect(String username, String password);



/**

 * 傳送訊息

 *

 * @param friendId: 接收訊息者id

 * @param msg:      訊息內容

 * @return: void

 */

void sendMsg(String friendId, String msg);

}

服務實現類:

@Slf4j

@Service

@Transactional(rollbackFor = Exception.class)

public class ChatServiceImpl implements IChatService {

@Override

public void loginConnect(String username, String password) {

    // 確保MobileIMSDK被初始化哦(整個APP生生命週期中只需呼叫一次哦)

    // 提示:在不退出APP的情況下退出登陸後再重新登陸時,請確保呼叫本方法一次,不然會報code=203錯誤哦!

    IMClientManager.getInstance().initMobileIMSDK();



    // * 非同步提交登陸名和密碼

    new LocalUDPDataSender.SendLoginDataAsync(username, password) {

        /**

         * 登陸資訊傳送完成後將呼叫本方法(注意:此處僅是登陸資訊傳送完成,真正的登陸結果要在非同步回撥中處理哦)。

         * @param code 資料傳送返回碼,0 表示資料成功發出,否則是錯誤碼

         */

        protected void fireAfterSendLogin(int code) {

            if(code == 0) {

                log.debug("資料傳送成功!");

            } else{

                log.error("資料傳送失敗。錯誤碼是:"+ code);

            }

        }

    }.execute();

}



@Override

public void sendMsg(String friendId, String msg) {

    // 傳送訊息(非同步提升體驗,你也可直接呼叫LocalUDPDataSender.send(..)方法傳送)

    new LocalUDPDataSender.SendCommonDataAsync(msg, friendId) {

        @Override

        protected void onPostExecute(Integer code) {

            if(code == 0) {

                log.debug("資料已成功發出!");

            } else{

                log.error("資料傳送失敗。錯誤碼是:"+ code + "!");

            }

        }

    }.execute();

}

}

五、編寫Controller進行測試

@RestController

@RequestMapping("/api")

@Api(tags = "聊天測試-介面")

public class ChatController {

@Autowired

private IChatService chatService;



@PostMapping(value = "/loginConnect", produces = Constants.CONTENT_TYPE)

@ApiOperation(value = "登陸請求", httpMethod = "POST", response = ApiResult.class)

public ApiResult loginConnect(@RequestParamString username, @RequestParamString password) {

    chatService.loginConnect(username, password);

    return ApiResult.ok();

}



@PostMapping(value = "/sendMsg", produces = Constants.CONTENT_TYPE)

@ApiOperation(value = "傳送訊息", httpMethod = "POST", response = ApiResult.class)

public ApiResult sendMsg(@RequestParam String friendId, @RequestParam String msg) {

    chatService.sendMsg(friendId, msg);

    return ApiResult.ok();

}

}

啟動專案,訪問:http://127.0.0.1:8080/swagger...

1) loginConnect介面:

任意輸入一個賬號密碼登入連線IM服務端:

控制檯日誌如下:

2)sendMsg介面:

給指定使用者傳送訊息:這裡由於只有一個客戶端,上一步登入了一個admin賬號,因此小編給admin賬號(也就是自己) 傳送訊息

控制檯日誌如下:

六、本文小結

關於整合可參考MobileIMSDK給出的文件一步一步實現。

該開源工程對應的官方文件比較齊全,需要哪個端,就去看對應端的手冊就好了。

1)Demo安裝和使用

客戶端Demo安裝和使用幫助(Android) [1]
客戶端Demo安裝和使用幫助(iOS) [2]
客戶端Demo安裝和使用幫助(Java) [3]
客戶端Demo演示和說明(H5) [4]
服務端Demo安裝和使用幫助 [5] new

2)開發者指南

客戶端開發指南(Android)
客戶端開發指南(iOS)
客戶端開發指南(Java)
客戶端開發指南(H5)
服務端開發指南

3)API文件

客戶端SDK API文件(Android):TCP版、UDP版
客戶端SDK API文件(iOS):TCP版、UDP版
客戶端SDK API文件(Java):TCP版、UDP版
客戶端SDK API文件(H5):點此進入
服務端SDK API文件

另外:作者給出了通過Java GUI程式設計實現的一個小demo,我們可以先將其執行起來,先體驗一下功能,程式碼量也不是太多,我們可以通過debug方式檢視執行流程。

清楚執行流程之後我們就可以將demo中的程式碼移植到我們自己的專案中加以修改運用於自己的業務中,切勿拿起就跑,否則一旦運氣不好,將浪費更多的時間去整合,這樣很不好!

最後:案例demo中相關程式碼註釋都有,這裡就簡單說下整個流程吧:

1)首先啟動IM服務端
2)使用者在客戶端登入一個使用者與服務端建立連線保持通訊( 客戶端ChatServiceImpl中loginConnect方法為登入連線服務端事件;服務端ServerEventListenerImpl中onUserLoginVerify方法為服務端接收的上線通知事件);
3)客戶端通過 ChatServiceImpl中sendMsg方法傳送一條訊息,如果對方線上能接收訊息則走服務端ServerEventListenerImpl中onTransferMessage4C2C方法,否則走onTransferMessage_RealTimeSendFaild方法;如果對方成功接收到訊息,客戶端將走MessageQoSEventImpl中messagesBeReceived事件,否則走messagesLost事件;
4)客戶端通過ChatMessageEvent中onRecieveMessage回撥事件接收訊息。

附:本文案例demo原始碼下載:

1)主地址:https://gitee.com/zhengqingya...
2)備地址:https://gitee.com/instant_mes...

附錄:更多IM聊天新手實踐程式碼

《跟著原始碼學IM(一):手把手教你用Netty實現心跳機制、斷線重連機制》
《跟著原始碼學IM(二):自已開發IM很難?手把手教你擼一個Andriod版IM》
《跟著原始碼學IM(三):基於Netty,從零開發一個IM服務端》
《跟著原始碼學IM(四):拿起鍵盤就是幹,教你徒手開發一套分散式IM系統》
《跟著原始碼學IM(五):正確理解IM長連線、心跳及重連機制,並動手實現》
《跟著原始碼學IM(六):手把手教你用Go快速搭建高效能、可擴充套件的IM系統》
《跟著原始碼學IM(七):手把手教你用WebSocket打造Web端IM聊天》
《跟著原始碼學IM(八):萬字長文,手把手教你用Netty打造IM聊天》
《跟著原始碼學IM(九):基於Netty實現一套分散式IM系統》
《跟著原始碼學IM(十):基於Netty,搭建高效能IM叢集(含技術思路+原始碼)》

相關文章