必要IdleStateHandlerハートビートチャネルが有効である、とUserAuthHandler MessageHandlerのを処理して、ログイン認証処理とメッセージ:パイプライン処理チェーンネッティーでハンドラ
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(defLoopGroup,
//编码解码器
new HttpServerCodec(),
//将多个消息转换成单一的消息对象
new HttpObjectAggregator(65536),
//支持异步发送大的码流,一般用于发送文件流
new ChunkedWriteHandler(),
//检测链路是否读空闲,配合心跳handler检测channel是否正常
new IdleStateHandler(60, 0, 0),
//处理握手和认证
new UserAuthHandler(),
//处理消息的发送
new MessageHandler()
);
}
でも、すべての着信チャネルのために、私たちは保存する必要が、その後の必要性は、大量のニュースチャンネルに依存します
public static void addChannel(Channel channel) {
String remoteAddr = NettyUtil.parseChannelRemoteAddr(channel);
System.out.println("addChannel:" + remoteAddr);
if (!channel.isActive()) {
logger.error("channel is not active, address: {}", remoteAddr);
}
UserInfo userInfo = new UserInfo();
userInfo.setAddr(remoteAddr);
userInfo.setChannel(channel);
userInfo.setTime(System.currentTimeMillis());
userInfos.put(channel, userInfo);
}
ログイン後、チャネルが有効チャネルとなり、チャネルが無効の後に削除されます
public static boolean saveUser(Channel channel, String nick, String password) {
UserInfo userInfo = userInfos.get(channel);
if (userInfo == null) {
return false;
}
if (!channel.isActive()) {
logger.error("channel is not active, address: {}, nick: {}", userInfo.getAddr(), nick);
return false;
}
// 验证用户名和密码
if (nick == null || password == null) {
return false;
}
LambdaQueryWrapper<Account> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(Account::getUsername, nick).eq(Account::getPassword, password);
Account account = accountMapperStatic.selectOne(lambdaQueryWrapper);
if (account == null) {
return false;
}
// 增加一个认证用户
userCount.incrementAndGet();
userInfo.setNick(nick);
userInfo.setAuth(true);
userInfo.setId(account.getId());
userInfo.setUsername(account.getUsername());
userInfo.setGroupNumber(account.getGroupNumber());
userInfo.setTime(System.currentTimeMillis());
// 注册该用户推送消息的通道
offlineInfoTransmitStatic.registerPull(channel);
return true;
}
チャネルが閉じられると、もはやメッセージを受信しません。unregisterPull消費者情報は、クライアントがもはやアセスチャットメッセージ、オフ書き込まれません。また、書き込みロック操作下からプラスがあり、チャネルを避けるためですまた、ここで、突然閉じられたチャネルをメッセージを送信し、これはエラーにつながります。
public static void removeChannel(Channel channel) {
try {
logger.warn("channel will be remove, address is :{}", NettyUtil.parseChannelRemoteAddr(channel));
//加上读写锁保证移除channel时,避免channel关闭时,还有别的线程对其操作,造成错误
rwLock.writeLock().lock();
channel.close();
UserInfo userInfo = userInfos.get(channel);
if (userInfo != null) {
if (userInfo.isAuth()) {
offlineInfoTransmitStatic.unregisterPull(channel);
// 减去一个认证用户
userCount.decrementAndGet();
}
userInfos.remove(channel);
}
} finally {
rwLock.writeLock().unlock();
}
}
シームレス4つのインターフェイスとして定義され、中間の保存および回送チャットメッセージを使用するこれらの四つの状態、ことなく、RabbitMQの、rocketmq、ActiveMQの間で切り替えるために。順次単一のメッセージチャット、グループチャットメッセージを送信し、クライアントがメッセージの受信を開始、クライアントがオフラインメッセージを受信しません。
public interface OfflineInfoTransmit {
void pushP2P(Integer userId, String message);
void pushGroup(String groupNumber, String message);
void registerPull(Channel channel);
void unregisterPull(Channel channel);
}
ここで、どのようにRabbitMQの、rocketmq、次のようなプロセスの中間ストアアンドフォワードチャットメッセージの1〜3種類のActiveMQの:
- シングルトークのモデルリファレンスモデルのスレッドプールユーザーがオンラインである場合には、チャネルを介してユーザに直接送信。ユーザがオフラインである場合、次のユーザーがメッセージミドルウェアから直接ラインにプルする場合、その後、中間貯蔵に送られます。両方のミドルウェアによって送信されたすべてのメッセージを有効にすることです。この比較の利点は、パフォーマンスが向上します
- グループチャットメッセージはミドルウェア、ミドルウェアアセスからクライアント・メッセージをメッセージングミドルウェアを完全に転送されます。あなたはまだ直接チャネルを介して、単一の、オンライン・ユーザーとして動作するようにお話ししたい場合は、操作は、このグループのユーザがオンラインであるかを決定するために、あまりにも面倒です
- あなたは、オンライン消費者を登録した場合は、ミドルウェアからのメッセージを取ります。それ以外の場合は、消費者を切断、メッセージはエンドユーザーの次の行に引っ張るために、ミドルウェアのまま。これは、オフラインメッセージを受け取る実現します。
- かかわらず、それは上記請求項3の処理フローに従うものミドルウェア、ミドルウェアの種類か否かの、上記の4つの方法は、シームレスに保存および回送メッセージに切り替えることができます。どちらの方法は、対応するノートを開く必要があります。