最近看以往在程序中编写的代码,发现有一个功能是使用socket通讯来实现的,而那个时候使用的是基于bio的阻塞io来实现的,最近在看netty,发现可以使用netty来使用nio的方式来实现,此博客记录一下netty学习的一个过程,此处实现一个简单的服务器和客户端之间的通讯。

实现要求:

1、服务器端监听9090端口

2、客户端连上服务端时,向服务端发送10条消息

3、使用netty自带的解码器解决tcp的粘包问题,避免接收到的数据是不完整的。(不了解tcp粘包的可以百度一下

实现:(代码的注释大致都写在了服务端这个类上)

一、引入netty的jar包

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.huan.netty</groupId>
<artifactId>netty-study</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>netty-study</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.6.Final</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.7</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.1.7</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
<version>1.1.7</version>
</dependency>
</dependencies>
</project>

 二、netty服务端的编写

@Slf4j
public class EchoServer { public static void main(String[] args) throws InterruptedException {
/** 此线程组用于服务单接收客户端的连接 */
EventLoopGroup boss = new NioEventLoopGroup(1);
/** 此线程组用于处理SocketChannel的读写操作 */
EventLoopGroup worker = new NioEventLoopGroup();
/** netty启动服务端的辅助类 */
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(boss, worker)//
.channel(NioServerSocketChannel.class)// 对应的是ServerSocketChannel类
.option(ChannelOption.SO_BACKLOG, 128)//
.handler(new LoggingHandler(LogLevel.TRACE))//
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ByteBuf delimiter = Unpooled.copiedBuffer("^^".getBytes(StandardCharsets.UTF_8));
// 表示客户端的数据中只要出现了^^就表示是一个完整的包,maxFrameLength这个表示如果在这个多个字节中还没有出现则表示数据有异常情况,抛出异常
ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, delimiter));
// 将接收到的数据转换成String的类型
ch.pipeline().addLast(new StringDecoder(StandardCharsets.UTF_8));
// 接收到的数据由自己的EchoServerHandler类进行处理
ch.pipeline().addLast(new EchoServerHandler());
}
});
// 绑定端口,同步等待成功
ChannelFuture future = bootstrap.bind(9090).sync();
log.info("server start in port:[{}]", 9090);
// 等待服务端链路关闭后,main线程退出
future.channel().closeFuture().sync();
// 关闭线程池资源
boss.shutdownGracefully();
worker.shutdownGracefully();
} @Slf4j
static class EchoServerHandler extends ChannelInboundHandlerAdapter {
private int counter = 0; /**
* 接收到数据的时候调用
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
String body = (String) msg;
log.info("this is: {} times receive cliemt msg: {}", ++counter, body);
body += "^^";
// 此处将数据写会到客户端,如果使用的是ctx.write方法这个只是将数据写入到缓冲区,需要再次调用ctx.flush方法
ctx.writeAndFlush(Unpooled.copiedBuffer(body.getBytes(StandardCharsets.UTF_8)));
} /** 当发生了异常时,次方法调用 */
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
log.error("error:", cause);
ctx.close();
}
} }

三、netty客户端代码的编写

    客户端在服务端链接建立成功后发送了10条数据给服务端

@Slf4j
public class EchoClient { public static void main(String[] args) throws InterruptedException {
EventLoopGroup group = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)//
.channel(NioSocketChannel.class)//
.option(ChannelOption.TCP_NODELAY, true)//
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ByteBuf delimiter = Unpooled.copiedBuffer("^^".getBytes(StandardCharsets.UTF_8));
ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, delimiter));
ch.pipeline().addLast(new StringDecoder());
ch.pipeline().addLast(new EchoClientHandler());
}
});
ChannelFuture future = bootstrap.connect("127.0.0.1", 9090).sync();
log.info("client connect server.");
future.channel().closeFuture().sync();
group.shutdownGracefully();
} @Slf4j
static class EchoClientHandler extends ChannelInboundHandlerAdapter {
private int counter;
private static final String ECHO_REQ = "hello server.服务器好啊.^^"; /**
* 客户端和服务器端TCP链路建立成功后,此方法被调用
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
for (int i = 0; i < 10; i++) {
ctx.writeAndFlush(Unpooled.copiedBuffer(ECHO_REQ.getBytes(StandardCharsets.UTF_8)));
}
} /**
* 接收到服务器端数据时调用
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
log.info("this is :{} revice server msg:{}", ++counter, msg);
} /**
* 发生异常时调用
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
log.error("client error:", cause);
ctx.close();
}
}
}

 四、测试

 服务器端和客户端都获取到了正确的数据,到此一个简单的echo工程就已经写完了。

netty入门实现简单的echo程序的更多相关文章

  1. [Netty] - Netty入门(最简单的Netty客户端/服务器程序)

    Java中的NIO是一种解决阻塞式IO问题的基本技术,但是NIO的编写对java程序员是有比较高的要求的.那么Netty就是一种简化操作的一个成熟的网络IO编程框架.这里简单介绍一个程序,代码是< ...

  2. [转]Netty入门(最简单的Netty客户端/服务器程序)

    Java中的NIO是一种解决阻塞式IO问题的基本技术,但是NIO的编写对java程序员是有比较高的要求的.那么Netty就是一种简化操作的一个成熟的网络IO编程框架.这里简单介绍一个程序,代码是< ...

  3. UNP学习笔记2——从一个简单的ECHO程序分析TCP客户/服务器之间的通信

    1 概述 编写一个简单的ECHO(回复)程序来分析TCP客户和服务器之间的通信流程,要求如下: 客户从标准输入读入一行文本,并发送给服务器 服务器从网络输入读取这个文本,并回复给客户 客户从网络输入读 ...

  4. 编写Java程序,实现一个简单的echo程序(网络编程TCP实践练习)

    首先启动服务端,客户端通过TCP的三次握手与服务端建立连接: 然后,客户端发送一段字符串,服务端收到字符串后,原封不动的发回给客户端. ECHO 程序是网络编程通信交互的一个经典案例,称为回应程序,即 ...

  5. netty入坑第一步:了解netty和编写简单的Echo服务器和客户端

    早期java API通过原生socket产生所谓的"blocking",大致过程是这样 这种的特点是每次只能处理一个请求,如果要实现多个请求并行,就还要分配一个新的线程来给每个客户 ...

  6. Netty入门二:开发第一个Netty应用程序

    Netty入门二:开发第一个Netty应用程序 时间 2014-05-07 18:25:43  CSDN博客 原文  http://blog.csdn.net/suifeng3051/article/ ...

  7. Java入门篇(一)——如何编写一个简单的Java程序

    最近准备花费很长一段时间写一些关于Java的从入门到进阶再到项目开发的教程,希望对初学Java的朋友们有所帮助,更快的融入Java的学习之中. 主要内容包括JavaSE.JavaEE的基础知识以及如何 ...

  8. 让Netty入门变得简单

    让Netty入门变得简单 https://mp.weixin.qq.com/s/MBnbLmCmFJo0QK9WNwXrXQ 如果先启动nettyClient就不会有nettyServer输出了: p ...

  9. Win32 程序开发入门:一个最简单的Win32程序

    一.什么是 Win32 Win32 是指 Microsoft Windows 操作系统的 32 位环境,与 Win64 都为 Windows 常见环境. 这里再介绍下 Win32 Applicatio ...

随机推荐

  1. Hash值和位运算

    一.Hash 1.md5是hash算法,不可逆,还原的是暴力穷举的方式解析的:加盐之后穷举也不能还原: 2.压缩映射会有重复,即哈希冲突: 二.ConcurrentHashMap 1.putIfAbs ...

  2. webService动态调用及返回至处理

    http://www.cnblogs.com/xffy1028/archive/2012/05/07/2487595.html using System; using System.Collectio ...

  3. python多继承简单方法

    class people(object): #建创一个人类 def __init__(self,name,age): self.name = name self.age = age def eat(s ...

  4. 【AGC025B】RGB Color

    [AGC025B]RGB Color 题面描述 Link to Atcoder Link to Luogu Takahashi has a tower which is divided into \( ...

  5. 洛谷P1019——单词接龙(DFS暴力搜索)

    https://www.luogu.org/problem/show?pid=1019#sub 题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母, ...

  6. 安卓开发 利用百度识图api进行物体识别(java版)

    之前的随笔中,已经实现了python版本调用api接口,之所以使用python是因为python比java要简洁. 但是我发现在使用过程中,chaquopy插件会弹出底部toast显示"un ...

  7. VSCode Remote-SSH 连接服务器

  8. Loadrunner拼装唯一值方法

    由于Loadrunner函数有限性,唯一值需要几个函数的字符串进行拼装,可实现流水号.订单号等等数值的唯一性.具体可见下列方法: 方法一: char OraderID[15];srand(time{N ...

  9. Docker DevOps实战:GitLab+Jenkins(2)- CI/CD相关配置

    Jenkins关联GitLab Gitlab仓库配置Webhooks 上传项目到GitLab,Jenkins构建

  10. Jmeter系列(2)- 代理服务器录制脚本

    操作步骤 step-1 添加代理服务器 step-2 添加线程组 step-3 添加录制控制器 HTTP代理服务器配置 - HTTP(S) Test Script Recorder TestPlan ...