在Netty学习笔记(一) 实现DISCARD服务中,我们使用Netty和Python实现了简单的丢弃DISCARD服务,这篇,我们使用Netty实现服务端和客户端交互的需求。

前置工作

开发环境

  • JDK8
  • Netty版本:5.0.0.Alpha2
  • 集成环境:IDEA
  • 构建工具:Gradle

依赖

    compile group: 'io.netty', name: 'netty-all', version: '5.0.0.Alpha2'
compile group: 'org.projectlombok', name: 'lombok', version: '1.18.0'

服务端

Netty服务器主要由两部分组成:

  • 配置服务器功能,如线程、端口
  • 实现服务器处理程序

服务端HandleAdapter

我们是首先实现服务端处理程序,实现Handle要求继承HandleAdapter,这里我们继承SimpleChannelInboundHandler<T>,下面是具体实现的代码信息,其每个函数的作用,我们只需要重写我们所需要的方法即可。


import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler; /**
* Netty 服务Handle
*
* @author tao
*/
@ChannelHandler.Sharable
public class EchoServiceHandle extends SimpleChannelInboundHandler<String> { /**
* 接收到新的消息
* @param ctx
* @param msg
* @throws Exception
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// 打印接收到的消息
System.out.println("Netty服务端接收到消息 " + msg);
// 回复消息
ctx.channel().writeAndFlush("Send ----> 客户端" + ctx.channel().id() + "你好,我已经接收到你发送的消息");
} /**
* 有新的连接加入
* @param ctx
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("接入新的Channel,id = " + ctx.channel().id());
} /**
* 服务端发生异常信息的时候
* @param ctx
* @param cause
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// 服务端发生异常
System.out.println("Netty 服务端发生异常 ,异常信息:" + cause);
ctx.close();
} @Override
protected void messageReceived(ChannelHandlerContext ctx, String msg) {}
}

服务端启动

在服务端的EchoServiceHandle完成之后,我们需要配置服务器的参数信息,比如端口等


import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import lombok.Data; /**
* @author tao
*/
@Data
public class EchoService { private int port; public void start() throws Exception {
EventLoopGroup boosGroup = new NioEventLoopGroup();
EventLoopGroup workGroup = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap
.group(boosGroup, workGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 128)
.childHandler(
new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
//字符串解码器
pipeline.addLast(new StringDecoder());
//字符串编码器
pipeline.addLast(new StringEncoder());
//服务端处理器
pipeline.addLast(new EchoServiceHandle());
}
});
ChannelFuture sync = bootstrap.bind(port).sync();
System.out.println("Netty Service start with " + port + "...");
sync.channel().closeFuture().sync();
} finally {
workGroup.shutdownGracefully();
boosGroup.shutdownGracefully();
}
} public static void main(String[] args) throws Exception {
EchoService service = new EchoService();
service.setPort(8080);
service.start();
}
}

启动后,我们可以看到启动信息如下:

Netty Service start with 8080...

客户端

客户端和服务端类似,可以相互参考学习.

客户端HandleAdapter

import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.CharsetUtil; @ChannelHandler.Sharable
public class EchoClientHandle extends SimpleChannelInboundHandler<String> { /**
* 连接创建成功的时候
* @param ctx
* @throws Exception
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelActive");
//连接成功后向服务端发送问候消息
ctx.channel().writeAndFlush(Unpooled.copiedBuffer("你好,这里是Netty客户端", CharsetUtil.UTF_8));
} /**
* 发生异常
* @param ctx
* @param cause
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
System.out.println("exceptionCaught");
cause.printStackTrace();
ctx.close();
} /**
* 接收到服务端发过来的数据
* @param ctx
* @param msg
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
//打印接收到的数据信息
System.out.println("channelRead = " + msg);
} @Override
protected void messageReceived(ChannelHandlerContext ctx, String msg) {}
}

客户端启动

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
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 io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j; import java.net.InetSocketAddress; /** @author tao */
@Data
@Accessors(chain = true)
@Slf4j
public class EchoClient { private int port; private String host; public void start() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap
.group(group)
.channel(NioSocketChannel.class)
.handler(
new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// 字符串解码器
pipeline.addLast(new StringDecoder());
// 字符串编码器
pipeline.addLast(new StringEncoder()); pipeline.addLast(new EchoClientHandle());
}
});
ChannelFuture sync = bootstrap.connect(new InetSocketAddress(host, port)).sync();
sync.channel().closeFuture().sync(); } catch (Exception e) {
e.printStackTrace();
} finally {
group.shutdownGracefully().sync();
}
} public static void main(String[] args) throws Exception {
EchoClient client = new EchoClient();
client.setHost("127.0.0.1").setPort(8080);
client.start();
}
}

效果

服务端效果

   Netty Service start with 8080...
接入新的Channel,id = c0d4f037
Netty服务端接收到消息 你好,这里是Netty客户端

客户端效果

channelActive
channelRead = Send ----> 客户端c0d4f037你好,我已经接收到你发送的消息

Netty学习笔记(二) 实现服务端和客户端的更多相关文章

  1. 红帽学习笔记[RHCE]OpenLDAP 服务端与客户端配置

    目录 OpenLDAP 服务端与客户端配置 关于LDIF 一个LDIF基本结构一个条目 属性 Object的类型 服务端 安装 生成证书 生成默认数据 修改基本的配置 导入基础数据 关于ldif的格式 ...

  2. Netty学习笔记(二)——netty组件及其用法

    1.Netty是 一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端. 原生NIO存在的问题 1) NIO的类库和API繁杂,使用麻烦:需要熟练掌握Selector.Se ...

  3. 《精通并发与Netty》学习笔记(02 - 服务端程序编写)

    上节我们介绍了开发netty项目所必需的开发环境及工具的使用,这节我们来写第一个netty项目 开发步骤 第一步:打开https://search.maven.org 找到netty依赖库 第二步:打 ...

  4. Netty学习笔记(二)

    只是代码,建议配合http://ifeve.com/netty5-user-guide/此网站观看 package com.demo.netty; import org.junit.Before;im ...

  5. Kafka学习笔记2--Kafka的服务端配置

    下载解压 kafka 后,在 kafka/config 下有 3 个配置文件与主题的生产.消费相关. server.properties--服务端配置 producer.properties--生产端 ...

  6. dubbo学习笔记二(服务调用)

    项目结构 代码示例 由于之前的IEchoService 的一个方法只是在服务端控制台打印,不便在浏览器测试,所以新添加的方法 api和服务端代码变更 public interface IEchoSer ...

  7. SVN1.6服务端和客户端安装配置指导

    本节向大家描述SVN1.6服务端和客户端安装配置步骤,随着SVN的快速发展,版本也进行了升级更新,本节就和大家一起学习一下SVN1.6服务端和客户端安装配置步骤,欢迎大家一起来学习.下面是具体介绍.1 ...

  8. Netty 学习(二):服务端与客户端通信

    Netty 学习(二):服务端与客户端通信 作者: Grey 原文地址: 博客园:Netty 学习(二):服务端与客户端通信 CSDN:Netty 学习(二):服务端与客户端通信 说明 Netty 中 ...

  9. Netty 学习(一):服务端启动 & 客户端启动

    Netty 学习(一):服务端启动 & 客户端启动 作者: Grey 原文地址: 博客园:Netty 学习(一):服务端启动 & 客户端启动 CSDN:Netty 学习(一):服务端启 ...

随机推荐

  1. [Swift]LeetCode229. 求众数 II | Majority Element II

    Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times. Note: The a ...

  2. [Swift]LeetCode976. 三角形的最大周长 | Largest Perimeter Triangle

    Given an array A of positive lengths, return the largest perimeter of a triangle with non-zero area, ...

  3. HTML入门教程,多年心血总结,一看就会

    笔者在武汉蚂蹄软件服务中心做软件开发多年,最近花一天时间总结出一套HTML入门级的教程,全篇没有任何废话,全部是精华,希望对你入门web开发有一定的帮助. HTML基本格式 <html> ...

  4. B+树的Copy-on-Write设计

    本文主要介绍B+树的Copy-On-Write,包括由来.设计思路和核心源码实现(以Xapian源码为例).中文的互联网世界里,对B树.B+树的科普介绍很丰富,但对它们在工业界的实际使用却几乎没有相关 ...

  5. Hive篇--搭建Hive集群

    一.前述 Hive中搭建分为三中方式 a)内嵌Derby方式 b)Local方式 c)Remote方式 三种方式归根到底就是元数据的存储位置不一样. 二.具体实现 a)内嵌Derby方式 使用derb ...

  6. Java异常处理:给程序罩一层保险

    文/沉默王二 人这一生,总会遇到一些不可预料的麻烦,这些麻烦可能会让我们遭受沉重的打击.为了减轻因此承受的负担,我们就会买保险. 本着负责任的态度,我们程序员在写代码的时候,都非常的严谨.但程序在运行 ...

  7. Elasticsearch Document

    1.  基本概念回顾 1.1.  Node 节点是一个服务器,它是集群的一部分,存储数据,并参与集群的索引和搜索功能 节点有一个名称标识,该名称在缺省情况下是在启动时分配给节点的随机全局惟一标识符(U ...

  8. SpringBoot修改Redis序列化方式

    前言 由于Springboot默认提供了序列化方式并不是非常理想,对于高要求的情况下,序列化的速度和序列化之后大小有要求的情况下,不能满足,所以可能需要更换序列化的方式. 这里主要记录更换序列化的方式 ...

  9. java中用MessageFormat格式化json字符串用占位符时出现的问题can't parse argument number

    在MessageFormat.format方法中组装jason数据字符串:{code:"w1",des:"w2"},起止分别有左大括号和右大括号. 直接写的点位 ...

  10. Java的类加载器种类(双亲委派)

    Java类加载器采用双亲委派模型: 1.启动类加载器:这个类加载器负责放在<JAVA_HOME>\lib目录中的,或者被-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别 ...