简书地址图文更清晰: 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. 痞子衡嵌入式:恩智浦i.MX RT1xxx系列MCU硬件那些事(2.3)- 串行NOR Flash下载算法(J-Link工具篇)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是J-Link工具下i.MXRT的串行NOR Flash下载算法设计. 在i.MXRT硬件那些事系列之<在串行NOR Flash X ...

  2. 《穷查理年鉴》金钱 & 生意 & 律师(关于金钱)

    金钱 025.钱还得快才会借得快. 030.钱和人有着复杂的友谊:人能让钱变坏,钱也能让人变坏. 034.绝望增加债务,勤奋偿还债务. 037.只有一无所有的人才会没有烦恼. 049.穷人为他的胃找食 ...

  3. JavaScript封装函数:获取下一个/上一个兄弟元素节点

    要求: 获得下一个/上一个兄弟元素节点,不包括文本节点等 解决IE兼容性问题 代码实现: 获得下一个兄弟元素节点: function getNextElement(element) { var el ...

  4. STM32之旅1——LED

    STM32之旅1--LED 学习了51单片机后,就要接触到更高级一点的单片机了,比如STM32,ST也有很多款单片机,现在用比较基础的学习--STM32F103RCT6. LED驱动 hal库的使用比 ...

  5. 创建自定义视图在Android矩阵效果画布教程

    介绍 下面是一个快速教程,教你如何在Android中创建自定义视图.自定义视图创建一个矩阵雨效果. 本教程发布在http://www.androidlearner.com/. 背景 下面是关于如何工作 ...

  6. 2440启动流程 <转载>

    韦东山 博客园 首页 订阅 管理 2440启动过程分析   2440启动过程分析 2440启动过程算是一个难点,不太容易理解,而对于2440启动过程的理解,影响了后面裸机代码执行流程的分析,从而看出2 ...

  7. 多路复用select和epoll的区别(转)

    先说下本文框架,先是问题引出,然后概括两个机制的区别和联系,最后介绍每个接口的用法 一.问题引出 联系区别 问题的引出,当需要读两个以上的I/O的时候,如果使用阻塞式的I/O,那么可能长时间的阻塞在一 ...

  8. 如何win10 上访问虚拟机(linux)上redis方法

    上一回linux上安装了redis,but在window上面连接不上/??? 配置了密码,不行, 防火墙端口打开了也不行??? 1. 首先要修改redis 的配置文件,找到bind节点,修改bind的 ...

  9. day64 Pyhton 框架Django 07

    day67 内容回顾 视图 1. CBV 定义 from django.views import View class Addpub(View): def get(self,request): sel ...

  10. 程序3-6 WERTYU

    把手放在键盘上时,稍不注意就会往右错一 位.这样,输入Q会变成输入W,输入J会变成输 入K等.键盘如图3-2所示. 输入一个错位后敲出的字符串(所有字母均 大写),输出打字员本来想打出的句子.输入保 ...