最近看以往在程序中编写的代码,发现有一个功能是使用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. IKE~多预共享密钥问题~解决方案

    原文链接:Configuring more than one Main-Mode Pre-Shared Key (PSK) *dialup* IPSec phase1 可能需要梯子来翻过高墙.文章内容 ...

  2. 在springboot pom文件配置过程,`spring-boot-maven-plugin`配置出错的问题解决及配置过程出现问题的一些思考

    在springboot pom文件配置过程,spring-boot-maven-plugin配置出错的问题解决及配置过程出现问题的一些思考 解决方法一: 也是最简单的方法,可能是maven没有来得及导 ...

  3. 借助AWR报告分析解决oracleCPU过高的问题

    原文地址:http://www.cnblogs.com/crystal-guoguo/p/4213458.html 简介:在oracle数据库中,有两个非常实用的自带监控工具EM(Enterprise ...

  4. scrum项目冲刺_day05总结

    摘要:今日完成任务. 1.语音识别完成 2.搜索功能实现了从数据库中的查询 总任务: 一.appUI页面(已完成) 二.首页功能: 1.图像识别功能(已完成) 2.语音识别功能(已完成) 3.垃圾搜索 ...

  5. Jenkins 进阶篇 - 任务关联

    有时候我们的一个任务里面会进行很多的步骤,例如构建一个后端的 Java 服务,可能会有代码静态扫描,静态扫描通过后会打包成 jar 或者 war 文件,打包成功后可能还会对制品进行存档备份,然后可能会 ...

  6. PHP匿名类的用法

    在PHP7之后,PHP中加入了匿名类的特性.匿名类和匿名方法让PHP成为了更现代化的语言,也让我们的代码开发工作越来越方便.我们先来看看匿名类的简单使用. // 直接定义 $objA = new cl ...

  7. 虚拟机安装配置centos7

    安装 https://blog.csdn.net/babyxue/article/details/80970526 主机环境预设 更换国内yum源 epel源 https://www.cnblogs. ...

  8. 鸿蒙内核源码分析(任务调度篇) | 任务是内核调度的单元 | 百篇博客分析OpenHarmony源码 | v4.05

    百篇博客系列篇.本篇为: v04.xx 鸿蒙内核源码分析(任务调度篇) | 任务是内核调度的单元 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度 ...

  9. CF1375F-Integer Game【交互】

    正题 题目链接:https://www.luogu.com.cn/problem/CF1375F 题目大意 给出\(a,b,c\).先手每次指定一个数\(k\),然后后手指定一个数字加上\(k\),若 ...

  10. 02-token

    随着互联网技术的发展,cookie+session形式的用户认真逐渐不适应需求的扩展.在当前分布式微服务广泛流行的场景下,显然这种cookie+session无法满足,因为各个服务之间无法相互获取se ...