网站流量分析,论坛网站怎么做排名,电工培训机构,巴彦淖尔seo一、前言
MobileIMSDK 是什么#xff1f;
MobileIMSDK 是一套专门为移动端开发的开源IM即时通讯框架#xff0c;超轻量级、高度提炼#xff0c;一套API优雅支持UDP 、TCP 、WebSocket 三种协议#xff0c;支持iOS、Android、H5、标准Java平台#xff0c;服务端基于Nett…一、前言
MobileIMSDK 是什么
MobileIMSDK 是一套专门为移动端开发的开源IM即时通讯框架超轻量级、高度提炼一套API优雅支持UDP 、TCP 、WebSocket 三种协议支持iOS、Android、H5、标准Java平台服务端基于Netty编写。
工程地址是
1Gitee码云地址https://www.oschina.net/p/mobileimsdk2Github托管地址https://github.com/JackJiang2011/MobileIMSDK
本文将实现
1基于springboot 集成 MobileIMSDK2开发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中引入 !-- [urlhttps://mvnrepository.com/artifact/com.google.code.gson/gson]https://mvnrepository.com/artifact/com.google.code.gson/gson[/url] --dependencygroupIdcom.google.code.gson/groupIdartifactIdgson/artifactIdversion2.8.5/version/dependency!-- MobileIMSDK所需jar包依赖[注这里是在本地lib中引入maven中央仓库中暂无此jar包]要与includeSystemScopetrue/includeSystemScope配合使用--dependencygroupIdcom.zhengqing/groupIdartifactIdMobileIMSDK4j/artifactIdscopesystem/scopesystemPath${project.basedir}/src/main/resources/lib/MobileIMSDK4j.jar/systemPath/dependencydependencygroupIdcom.zhengqing/groupIdartifactIdMobileIMSDKServerX_meta/artifactIdscopesystem/scopesystemPath${project.basedir}/src/main/resources/lib/MobileIMSDKServerX_meta.jar/systemPath/dependencydependencygroupIdcom.zhengqing/groupIdartifactIdswing-worker-1.2(1.6-)/artifactIdscopesystem/scopesystemPath${project.basedir}/src/main/resources/lib/swing-worker-1.2(1.6-).jar/systemPath/dependencydependencygroupIdcom.zhengqing/groupIdartifactIdMobileIMSDKServerX_netty/artifactIdscopesystem/scopesystemPath${project.basedir}/src/main/resources/lib/MobileIMSDKServerX_netty.jar/systemPath/dependency
plugins!-- maven打包插件 - 将整个工程打成一个 fatjar --plugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactId!-- 作用:项目打成jar同时把本地jar包也引入进去 --configurationincludeSystemScopetrue/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的整数*/Overridepublic 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 “会话”*/Overridepublic 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 “会话”*/Overridepublic void onUserLogoutAction_CallBack(String userId, Object obj, Channel session) {logger.debug(【DEBUG_回调通知OnUserLogoutAction_CallBack】用户 userId 离线了);}/*** 通用数据回调方法定义客户端发给服务端的即接收user_id0.* p* MobileIMSDK在收到客户端向user_id0(即接收目标是服务器)的情况下通过* 本方法的回调通知上层。上层通常可在本方法中实现如添加好友请求等业务实现。** p stylebackground:#fbf5ee;border-radius:4px;* bfont color#ff0000【版本兼容性说明】/font/b本方法用于替代v3.x中的以下方法br* codepublic 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*/Overridepublic boolean onTransBuffer_C2S_CallBack(Protocal p, Channel session) {// 接收者uidString userId p.getTo();// 发送者uidString from_user_id p.getFrom();// 消息或指令内容String dataContent p.getDataContent();// 消息或指令指纹码即唯一IDString 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 stylebackground:#fbf5ee;border-radius:4px;* bfont color#ff0000【版本兼容性说明】/font/b本方法用于替代v3.x中的以下方法br* codepublic 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*/Overridepublic void onTransBuffer_C2C_CallBack(Protocal p) {// 接收者uidString userId p.getTo();// 发送者uidString from_user_id p.getFrom();// 消息或指令内容String dataContent p.getDataContent();// 消息或指令指纹码即唯一IDString 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此方法存的意义何在/bbr* 发生此种情况的场景可能是对方确实不在线那么此方法里就可以作为离线消息处理了、* 或者在发送时判断对方是在线的但服务端在发送时却没有成功这种情况就可能是通信错误* 或对方非正常通出但尚未到达会话超时时限。bru应用层在此方法里实现离线消息的处理即可/u** p stylebackground:#fbf5ee;border-radius:4px;* bfont color#ff0000【版本兼容性说明】/font/b本方法用于替代v3.x中的以下方法br* codepublic 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*/Overridepublic boolean onTransBuffer_C2C_RealTimeSendFaild_CallBack(Protocal p) {// 接收者uidString userId p.getTo();// 发送者uidString from_user_id p.getFrom();// 消息或指令内容String dataContent p.getDataContent();// 消息或指令指纹码即唯一IDString 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);Overridepublic void messagesLost(ArrayListProtocal lostMessages) {logger.debug(【DEBUG_QoS_S2C事件】收到系统的未实时送达事件通知当前共有 lostMessages.size() 个包QoS保证机制结束判定为【无法实时送达】);}Overridepublic 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中默认就是falseServerLauncher.bridgeEnabled false;// TODO 跨服桥接器MQ的URI本参数只在ServerLauncher.bridgeEnabled为true时有意义// BridgeProcessor.IMMQ_URI amqp://js:19844713192.168.31.190;}// 实例构造方法public ServerLauncherImpl() throws IOException {super();}/*** 初始化消息处理事件监听者.*/Overrideprotected void initListeners() {// ** 设置各种回调事件处理实现类this.setServerEventListener(newServerEventListenerImpl());this.setServerMessageQoSEventListener(newMessageQoSEventS2CListnerImpl());}}
3.4 服务端启动类
温馨小提示这里由于小编将服务端和客户端集成在同一个项目中因此如下配置
SpringBoot的CommandLineRunner接口主要用于实现在服务初始化后去执行一段代码块逻辑run方法这段初始化代码在整个应用生命周期内只会执行一次Order(value 1) 按照一定的顺序去执行value值越小越先执行
Slf4jComponentOrder(value 1)public class ChatServerRunner implements CommandLineRunner {Overridepublic void run(String... strings) throws Exception {log.info( ↓↓↓↓↓↓ 启动MobileIMSDK服务端 ↓↓↓↓↓↓ );// 实例化后记得startup哦单独startup()的目的是让调用者可以延迟决定何时真正启动IM服务final ServerLauncherImpl sli new ServerLauncherImpl();// 启动MobileIMSDK服务端的Demosli.startup();// 加一个钩子确保在JVM退出时释放netty的资源Runtime.getRuntime().addShutdownHook(newThread(sli::shutdown));}}
如果服务端与客户端不在同一个项目 服务端可直接通过如下方式启动即可~ 四、开发客户端 4.1 客户端与IM服务端连接事件
Slf4jpublic class ChatBaseEventImpl implements ChatBaseEvent {Overridepublic void onLoginMessage(int dwErrorCode) {if(dwErrorCode 0) {log.debug(IM服务器登录/连接成功);} else{log.error(IM服务器登录/连接失败错误代码 dwErrorCode);}}Overridepublic void onLinkCloseMessage(int dwErrorCode) {log.error(与IM服务器的网络连接出错关闭了error dwErrorCode);}}
4.2 接收消息事件
Slf4jpublic class ChatTransDataEventImpl implements ChatTransDataEvent {Overridepublic void onTransBuffer(String fingerPrintOfProtocal, String userid, String dataContent, inttypeu) {log.debug([typeu typeu ]收到来自用户 userid 的消息: dataContent);}Overridepublic void onErrorResponse(int errorCode, String errorMsg) {log.debug(收到服务端错误消息errorCode errorCode , errorMsg errorMsg);}}
4.3 消息是否送达事件
Slf4jpublic class MessageQoSEventImpl implements MessageQoSEvent {Override// 对方未成功接收消息的回调事件 lostMessages存放消息内容public void messagesLost(ArrayListProtocal 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);}
服务实现类
Slf4jServiceTransactional(rollbackFor Exception.class)public class ChatServiceImpl implements IChatService {Overridepublic void loginConnect(String username, String password) {// 确保MobileIMSDK被初始化哦整个APP生生命周期中只需调用一次哦// 提示在不退出APP的情况下退出登陆后再重新登陆时请确保调用本方法一次不然会报code203错误哦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();}Overridepublic void sendMsg(String friendId, String msg) {// 发送消息异步提升体验你也可直接调用LocalUDPDataSender.send(..)方法发送new LocalUDPDataSender.SendCommonDataAsync(msg, friendId) {Overrideprotected void onPostExecute(Integer code) {if(code 0) {log.debug(数据已成功发出);} else{log.error(数据发送失败。错误码是 code );}}}.execute();}}
五、编写Controller进行测试
RestControllerRequestMapping(/api)Api(tags 聊天测试-接口)public class ChatController {Autowiredprivate 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-ui.html 1 loginConnect接口
任意输入一个账号密码登录连接IM服务端 控制台日志如下 2sendMsg接口
给指定用户发送消息这里由于只有一个客户端上一步登录了一个admin账号因此小编给admin账号(也就是自己) 发送消息 控制台日志如下 六、本文小结
关于集成可参考MobileIMSDK给出的文档一步一步实现。
该开源工程对应的官方文档比较齐全需要哪个端就去看对应端的手册就好了。
1Demo安装和使用
客户端Demo安装和使用帮助(Android) [1]客户端Demo安装和使用帮助(iOS) [2]客户端Demo安装和使用帮助(Java) [3]客户端Demo演示和说明(H5) [4]服务端Demo安装和使用帮助 [5] new
2开发者指南
客户端开发指南(Android)客户端开发指南(iOS)客户端开发指南(Java)客户端开发指南(H5)服务端开发指南
3API文档
客户端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主地址java-workspace: 存放案例demo代码2备地址java-workspace: 存放案例demo代码
附录更多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集群含技术思路源码》