简书地址图文更清晰: 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聊天的更多相关文章

  1. Netty 实现 WebSocket 聊天功能

    上一次我们用Netty快速实现了一个 Java 聊天程序(见http://www.waylau.com/netty-chat/).现在,我们要做下修改,加入 WebSocket 的支持,使它可以在浏览 ...

  2. 【开源】Netty轻松实现聊天室,附带数据记录,聊天历史

    阅读本文约“2.5分钟” 听说快七夕······ 不对,这不是今天的主题,嘿嘿. 今天说说一个小的网页聊天室,功能如下 群聊无限制 记录用户群聊信息 下次登录显示聊天历史 消息发送速度(光速) 聊天历 ...

  3. Netty多人聊天室

    在简单聊天室的代码中修改ChatServerHandler类,就可以模拟多人聊天的功能 package com.cppdy.server; import io.netty.channel.Channe ...

  4. 一个基于netty的websocket聊天demo

    这里,仅仅是一个demo,模拟客户基于浏览器咨询卖家问题的场景,但是,这里的demo中,卖家不是人,是基于netty的程序(我就叫你uglyRobot吧),自动回复了客户问的问题. 项目特点如下: 1 ...

  5. netty使用以及聊天小程序

    <从零开始搭建游戏服务器>Netty导入创建Socket服务器 Netty入门教程 Netty 聊天小程序

  6. Netty 仿QQ聊天室 (实战二)

    Netty 聊天器(百万级流量实战二):仿QQ客户端 疯狂创客圈 Java 分布式聊天室[ 亿级流量]实战系列之15 [博客园 总入口 ] 源码IDEA工程获取链接:Java 聊天室 实战 源码 写在 ...

  7. WebSocket+Netty构建web聊天程序

    WebSocket 传统的浏览器和服务器之间的交互模式是基于请求/响应的模式,虽然可以使用js发送定时任务让浏览器在服务器中拉取但是弊端很明显,首先就是不等避免的延迟,其次就是频繁的请求,让服务器的压 ...

  8. netty实现消息中心(二)基于netty搭建一个聊天室

    前言 上篇博文(netty实现消息中心(一)思路整理 )大概说了下netty websocket消息中心的设计思路,这篇文章主要说说简化版的netty聊天室代码实现,支持群聊和点对点聊天. 此demo ...

  9. 利用netty简单实现聊天室

    1.导入依赖包 <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</a ...

随机推荐

  1. C# Redis分布式锁(RedLock) - 多节点

    Redis单节点的分布式锁只需要注意三点就可以了: 1.加锁并设置锁的过期时间必须是原子操作; 2.锁的value值必须要有唯一性; 3.释放锁的时候要验证其value值,不是自己加的锁不能释放. 但 ...

  2. 035 01 Android 零基础入门 01 Java基础语法 04 Java流程控制之选择结构 02 多重if结构

    035 01 Android 零基础入门 01 Java基础语法 04 Java流程控制之选择结构 02 多重if结构 本文知识点:Java中的多重if结构 选择结构回顾 if选择结构 注意: 1.条 ...

  3. Vue自定义Popup弹窗组件|vue仿ios、微信弹窗|vue右键弹层

    基于vue.js构建的轻量级Vue移动端弹出框组件Vpopup vpopup 汇聚了有赞Vant.京东NutUI等Vue组件库的Msg消息框.Popup弹层.Dialog对话框.Toast弱提示.Ac ...

  4. 字节码暴力破解censum(老版本)

    声明 事先声明,本文仅提供破解方法以供个人及读者们学习Java字节码,不提倡破解程序. 本文是个人学习掘金小册张师傅的<JVM字节码从入门到精通>后,作为一个实践的记录,并无恶意. 关于c ...

  5. 解决mvn clean install的报错The packaging for this project did not assign a file to the build artifact

    解决mvn clean install的报错The packaging for this project did not assign a file to the build artifact

  6. ansible-playbook调试

    1. ansible-playbook  1)ansible-playbook的语法检测 1 [root@test-1 bin]# ansible-playbook --syntax-check ng ...

  7. DM9000时序设置

    想了解一下DM9000的移植修改原理,所以分析了一下时序图和引脚连接   首先看一下DM9000的引脚和MINI2440的引脚连接   DM9000  MINI2440 功能描述   SD0   DA ...

  8. HTML常用标签(上)

    HTML常用标签 1. web标准 1.1 web标准的构成 主要包括结构.表现和行为三个方面. 标准 说明 结构 用于对网页元素进行整理和分类(HTML) 表现 用于设置网页元素的外观样式(CSS) ...

  9. golang通过cgo调用lua

    目录 1.前期准备 2.测试go代码 3.完成的一个学习项目 4.总结 1.前期准备 1.第三方库:https://github.com/aarzilli/golua 2.下载lua源码:https: ...

  10. Android ContentProvider 基本原理和使用详解

    ContentProvider(内容提供者)是 Android 的四大组件之一,管理 Android 以结构化方式存放的数据,以相对安全的方式封装数据(表)并且提供简易的处理机制和统一的访问接口供其他 ...