使用netty实现im聊天
简书地址图文更清晰: https://www.jianshu.com/p/f455814f3c40
1、新建maven工程
2、引入maven依赖
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.49.Final</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.68</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
3、定义消息体MsgBody
public class MsgBody {
//发送人名称
private String sendUserName;
private String msg;
public String getSendUserName() {
return sendUserName;
}
public void setSendUserName(String sendUserName) {
this.sendUserName = sendUserName;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
4、新建服务器端的NettyServer和ServerHandler
/**
* netty的服务器
* @Author: yeyongjian
* @Date: 2020-05-03 23:34
*/
public class NettyServer {
private int port;
public NettyServer(int port) {
this.port = port;
bind();
}
private void bind() {
EventLoopGroup boss = new NioEventLoopGroup();
EventLoopGroup worker = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(boss, worker);
bootstrap.channel(NioServerSocketChannel.class);
bootstrap.option(ChannelOption.SO_BACKLOG, 1024); // 连接数
bootstrap.option(ChannelOption.TCP_NODELAY, true); // 不延迟,消息立即发送
bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true); // 长连接
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel){
ChannelPipeline p = socketChannel.pipeline();
ServerHandler serverHandler = new ServerHandler();
p.addLast(serverHandler);// 添加NettyServerHandler,用来处理Server端接收和处理消息的逻辑
}
});
ChannelFuture channelFuture = bootstrap.bind(port).sync();
if (channelFuture.isSuccess()) {
System.err.println("启动Netty服务成功,端口号:" + this.port);
}
// 关闭连接
channelFuture.channel().closeFuture().sync();
} catch (Exception e) {
System.err.println("启动Netty服务异常,异常信息:" + e.getMessage());
e.printStackTrace();
} finally {
boss.shutdownGracefully();
worker.shutdownGracefully();
}
}
public static void main(String[] args) throws InterruptedException {
new NettyServer(10086);
}
}
import com.alibaba.fastjson.JSONObject;
import com.eujian.im.MsgBody;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelId;
import io.netty.channel.SimpleChannelInboundHandler;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
/**
* 服务器的处理器
* @Author: yeyongjian
* @Date: 2020-05-03 23:35
*/
public class ServerHandler extends SimpleChannelInboundHandler {
//连接id与容器的关系
private static Map<String, ChannelHandlerContext> map = new HashMap<>();
@Override
protected void channelRead0(ChannelHandlerContext ctx, Object msg) {
Channel channel = ctx.channel();
ChannelId id = channel.id();
map.put(id.toString(),ctx);
ByteBuf buf = (ByteBuf) msg;
String recieved = getMessage(buf);
MsgBody msgBody = JSONObject.parseObject(recieved, MsgBody.class);
String format = String.format("服务器接收到客户端消息,发送人:%s,发送信息:%s", msgBody.getSendUserName(), msgBody.getMsg());
System.err.println(format);
map.forEach((k,v)->{
try {
if(id.toString().equals(k)){
return;
}
MsgBody sendMsgBody = new MsgBody();
sendMsgBody.setSendUserName(msgBody.getSendUserName());
sendMsgBody.setMsg(msgBody.getMsg());
v.writeAndFlush(getSendByteBuf(JSONObject.toJSONString(sendMsgBody)));
System.err.println("服务器回复消息:"+JSONObject.toJSONString(sendMsgBody));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
});
}
/*
* 从ByteBuf中获取信息 使用UTF-8编码返回
*/
private String getMessage(ByteBuf buf) {
byte[] con = new byte[buf.readableBytes()];
buf.readBytes(con);
try {
return new String(con, "UTF8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return null;
}
}
private ByteBuf getSendByteBuf(String message)
throws UnsupportedEncodingException {
byte[] req = message.getBytes("UTF-8");
ByteBuf pingMessage = Unpooled.buffer();
pingMessage.writeBytes(req);
return pingMessage;
}
}
5、新建客户端代码
import com.alibaba.fastjson.JSONObject;
import com.eujian.im.MsgBody;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import java.io.UnsupportedEncodingException;
public class NettyClientHandler extends SimpleChannelInboundHandler {
private ByteBuf firstMessage;
private ChannelHandlerContext ctx;
private String userName;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public void sendMsg(String str){
byte[] data = str.getBytes();
firstMessage = Unpooled.buffer();
firstMessage.writeBytes(data);
ctx.writeAndFlush(firstMessage);
}
@Override
public void channelActive(ChannelHandlerContext ctx) {
this.ctx= ctx;
MsgBody msgBody = new MsgBody();
msgBody.setSendUserName(userName);
msgBody.setMsg("进入聊天室");
byte[] data = JSONObject.toJSONString(msgBody).getBytes();
firstMessage = Unpooled.buffer();
firstMessage.writeBytes(data);
ctx.writeAndFlush(firstMessage);
}
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object msg){
ByteBuf buf = (ByteBuf) msg;
String rev = getMessage(buf);
MsgBody msgBody = JSONObject.parseObject(rev, MsgBody.class);
String format = String.format("客户端收到服务器消息,发送人:%s,发送信息:%s", msgBody.getSendUserName(), msgBody.getMsg());
System.err.println(format);
}
private String getMessage(ByteBuf buf) {
byte[] con = new byte[buf.readableBytes()];
buf.readBytes(con);
try {
return new String(con, "UTF8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return null;
}
}
}
import com.alibaba.fastjson.JSONObject;
import com.eujian.im.MsgBody;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.util.Scanner;
public class NettyClient {
public NettyClientHandler nettyClientHandler;
/*
* 服务器端口号
*/
private int port;
private String sendUserName;
/*
* 服务器IP
*/
private String host;
public NettyClient(int port, String host, String sendUserName) throws InterruptedException {
this.port = port;
this.host = host;
this.sendUserName = sendUserName;
start();
}
private void start() throws InterruptedException {
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.channel(NioSocketChannel.class);
bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
bootstrap.group(eventLoopGroup);
bootstrap.remoteAddress(host, port);
bootstrap.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel)
throws Exception {
nettyClientHandler = new NettyClientHandler();
nettyClientHandler.setUserName(sendUserName);
socketChannel.pipeline().addLast(nettyClientHandler);
}
});
ChannelFuture channelFuture = bootstrap.connect(host, port).sync();
if (channelFuture.isSuccess()) {
new Thread(new Runnable() {
@Override
public void run() {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()){
MsgBody msgBody = new MsgBody();
msgBody.setSendUserName(sendUserName);
msgBody.setMsg(sc.next());
nettyClientHandler.sendMsg(JSONObject.toJSONString(msgBody));
}
}
}).start();
System.err.println(sendUserName+"连接服务器成功");
}
channelFuture.channel().closeFuture().sync();
} finally {
eventLoopGroup.shutdownGracefully();
}
}
}
6、新建2个main函数,模拟两个客户端
public static void main(String[] args) throws InterruptedException {
new NettyClient(10086, "localhost","tom");
}
}
public static void main(String[] args) throws InterruptedException {
new NettyClient(10086, "localhost","jack");
}
}
7、启动nettyServer,main1和main2
在main1输入 jack,你好,
在main2输入 tom,hello,我很好
server显示

main1显示

main2显示
码云: https://gitee.com/guoeryyj/netty-im.git
欢迎关注我的微信公众号:进阶者euj
使用netty实现im聊天的更多相关文章
- Netty 实现 WebSocket 聊天功能
上一次我们用Netty快速实现了一个 Java 聊天程序(见http://www.waylau.com/netty-chat/).现在,我们要做下修改,加入 WebSocket 的支持,使它可以在浏览 ...
- 【开源】Netty轻松实现聊天室,附带数据记录,聊天历史
阅读本文约“2.5分钟” 听说快七夕······ 不对,这不是今天的主题,嘿嘿. 今天说说一个小的网页聊天室,功能如下 群聊无限制 记录用户群聊信息 下次登录显示聊天历史 消息发送速度(光速) 聊天历 ...
- Netty多人聊天室
在简单聊天室的代码中修改ChatServerHandler类,就可以模拟多人聊天的功能 package com.cppdy.server; import io.netty.channel.Channe ...
- 一个基于netty的websocket聊天demo
这里,仅仅是一个demo,模拟客户基于浏览器咨询卖家问题的场景,但是,这里的demo中,卖家不是人,是基于netty的程序(我就叫你uglyRobot吧),自动回复了客户问的问题. 项目特点如下: 1 ...
- netty使用以及聊天小程序
<从零开始搭建游戏服务器>Netty导入创建Socket服务器 Netty入门教程 Netty 聊天小程序
- Netty 仿QQ聊天室 (实战二)
Netty 聊天器(百万级流量实战二):仿QQ客户端 疯狂创客圈 Java 分布式聊天室[ 亿级流量]实战系列之15 [博客园 总入口 ] 源码IDEA工程获取链接:Java 聊天室 实战 源码 写在 ...
- WebSocket+Netty构建web聊天程序
WebSocket 传统的浏览器和服务器之间的交互模式是基于请求/响应的模式,虽然可以使用js发送定时任务让浏览器在服务器中拉取但是弊端很明显,首先就是不等避免的延迟,其次就是频繁的请求,让服务器的压 ...
- netty实现消息中心(二)基于netty搭建一个聊天室
前言 上篇博文(netty实现消息中心(一)思路整理 )大概说了下netty websocket消息中心的设计思路,这篇文章主要说说简化版的netty聊天室代码实现,支持群聊和点对点聊天. 此demo ...
- 利用netty简单实现聊天室
1.导入依赖包 <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</a ...
随机推荐
- 03 以Hello World为例,分析C语言的最小的程序结构
C程序主要包含的部分 预处理器指令 函数 变量 语句 & 表达式 注释 C Hello World 实例 如下程序,可以在屏幕输出短句"Hello World" #incl ...
- Github 太狠了,居然把 "master" 干掉了!
前段时间栈长有看到 Github 和 master 分支变更的新闻,当时没有注意细节,直到今天我创建仓库时: 看了半天感觉有点不对劲啊... 怎么 master 不见了,之前默认主干分支名称都是叫 m ...
- RxJS入门2之Rxjs的安装
RxJS V6.0+ 安装 RxJS 的 import 路径有以下 5 种: 1.创建 Observable 的方法.types.schedulers 和一些工具方法 import { Observa ...
- Node.js安装及环境配置 for winer
Node.js安装及环境for Windows 一.安装环境 1.本机系统:Windows 10 Pro(64位) 2.Node.js:v6.9.2LTS(64位) 二.安装Node.js步骤 1.下 ...
- Informatic 内些坑
1. 工作流调用工作流(可实现无规则时间点自由调度) pmcmd startworkflow -sv 集成服务名称 -d 配置域名称 -u Administrator -p Administrato ...
- Python数据类型--字典(dict)
Python中的字典是键值对(key-value)的无序集合.每个元素包含"键"和"值"两部分,这两部分之间使用冒号分隔,表示一种对应关系.不同元素之间用逗号分 ...
- ASP课程实例1——简易的手机号抽奖
本程序用到了最基本的vbscript函数. 请大家注意它们的用法并熟悉asp网页的基本结构. inputbox,mid() ,replace(),rnd(),fix(),document.write ...
- 多测师讲解自动化测试 _RF关键字001_(上)_高级讲师肖sir
讲解案例1: Open Browser http://www.baidu.com gc #打开浏览器 Maximize Browser Window #窗口最大化 sleep 2 #线程等待2秒 In ...
- 多测师讲解python _unttest框架002(结合项目实战)_高级讲师肖sir
第一种调用方法: if __name__ == '__main__':# #第一种运行方法:运行所有的用例 import unittestfrom selenium import webdriverf ...
- linux学习(二)--setup.s
执行过bootsect.s,加载了所有系统代码之后,开始向32位模式转变,为main函数的调用做准备,同样,附上图往下看 1 INITSEG = 0x9000 ! we move boot here ...
