`

netty入门实现简单的echo程序

阅读更多

     最近看以往在程序中编写的代码,发现有一个功能是使用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工程就已经写完了。

  • 大小: 126.8 KB
分享到:
评论

相关推荐

    Netty入门与实战:仿写微信IM即时通讯系统

    Netty实现IM通讯

    Netty入门教程文档

    Netty入门教程文档 Netty是Java的网络编程框架,广泛应用于数据采集服务中,本文将对Netty的基本概念和应用进行详细介绍,并将其与ETL技术结合,讲解如何使用Netty进行数据流转和处理。 1. ETL概述 ETL(Extract...

    Netty 入门与实战:仿写微信 IM 即时通讯系统.rar

    Netty 入门与实战:仿写微信 IM 即时通讯系统,掘金小册子,netty教程。章节齐全无缺失,排版非常不错。 1.仿微信IM系统简介 1 2.Netty是什么? 2 3.服务端启动流程 8 4.客户端启动流程 11 5.实战:客户端与服务端双向...

    Netty 入门与实战:仿写微信 IM 即时通讯系统

    Netty是Java领域中一个高效的异步事件驱动的网络应用程序框架,它为快速开发可维护的高性能协议服务器和客户端提供了丰富的组件和API。 首先,我们要理解Netty的核心设计理念。Netty采用了非阻塞I/O模型,利用Java ...

    netty入门到精通.txt

    netty入门到精通

    Netty 入门与实战:仿写微信 IM 即时通讯系统.zip

    《Netty 入门与实战:仿写微信 IM 即时通讯系统》是一本深入浅出的教程,旨在帮助读者掌握使用Netty构建高效、稳定、高性能的即时通讯系统的方法。通过模仿微信IM的实现,本书将理论知识与实践案例相结合,使读者...

    Netty 入门与实战:仿写微信 IM 即时通讯系统.pdf

    Netty 入门与实战:仿写微信 IM 即时通讯系统

    Netty 入门与实战

    Netty 是一个高性能、异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。这个框架在Java领域广泛应用于构建高并发、低延迟的网络应用,如分布式系统、游戏服务器、金融交易系统等。...

    netty入门进阶之前

    Netty 是一个高性能、异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。在深入探讨Netty之前,我们先来理解一些基础概念。 1. **ByteBuf**: ByteBuf是Netty中用于处理网络数据传输...

    Netty的入门经典例子

    Netty 的主要特点是基于 NIO 的客户、服务器端编程框架,使用 Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户、服务端应用。Netty 支持 TCP 和 UDP 的 socket 服务,并且在处理大容量...

    netty入门示例工程

    本工程采用maven+netty4.1.0+PrefixedStringDecoder+json技术,包括客户端和服务端。先运行服务端SampleServer,再去等客户端SampleClient。示例中发的是心跳包,其中消息格式定义为msgType + msgNo + content(json...

    Netty-入门Netty编码

    Netty 是一个高性能、异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。这个教程将引导我们入门 Netty 编码,让我们深入理解其核心概念和实际应用。 首先,Netty 的核心是其设计...

    Netty+maven的入门程序

    在本入门程序中,我们将深入探讨如何结合 Maven 和 Eclipse 创建一个简单的 Netty 项目。 首先,让我们了解 Maven。Maven 是一个项目管理和综合工具,它通过提供一组规则和标准化的构建过程来简化 Java 项目的构建...

    Netty+入门与实战:仿写微信+IM+即时通讯系统.rar

    《Netty+入门与实战:仿写微信+IM+即时通讯系统》是一本专注于使用Netty框架构建即时通讯系统的教程。Netty是一个高性能、异步事件驱动的网络应用框架,适用于开发服务器和客户端的Java应用。它极大地简化了网络编程...

    Netty 快速入门系列-源码

    Netty快速入门系列源码, 参考 https://blog.csdn.net/netcobol ...允许快速简单的开发网络应用程序。例如:服务端和客户端之间的协议。它最牛逼的地方在于简化了网络编程规范。例如:TCP和UDP的Socket服务

    netty实现简易tomcat

    Netty 是一个高性能、异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。在本项目中,我们将探讨如何利用 Netty 实现一个简易版的 Tomcat,即一个基础的 HTTP 服务器容器。Tomcat 是...

Global site tag (gtag.js) - Google Analytics