Socket通讯-Netty框架实现Java通讯
Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。
也就是说,Netty 是一个基于NIO的客户、服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用。Netty相当简化和流线化了网络应用的编程开发过程,例如,TCP和UDP的socket服务开发。
“快速”和“简单”并不用产生维护性或性能上的问题。Netty 是一个吸收了多种协议的实现经验,这些协议包括FTP,SMTP,HTTP,各种二进制,文本协议,并经过相当精心设计的项目,最终,Netty 成功的找到了一种方式,在保证易于开发的同时还保证了其应用的性能,稳定性和伸缩性。
本文的目的
使用Netty实现一个Socket通讯,包括客户端和服务端,通过服务端进行监听,客户端发送信息,服务端可进行接收,并进行返回数据,完成一个完整的通讯。
工程结构
POM文件配置
<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.taowd.socket</groupId>
<artifactId>SocketDemo2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.6.Final</version>
</dependency>
</dependencies>
</project>
服务端代码
EchoServer.java
package Server;
import java.nio.charset.Charset;
import io.netty.bootstrap.ServerBootstrap;
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.NioServerSocketChannel;
import io.netty.handler.codec.bytes.ByteArrayEncoder;
import io.netty.handler.codec.string.StringEncoder;public class EchoServer {
private final int port;<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">EchoServer</span><span class="hljs-params">(<span class="hljs-keyword">int</span> port)</span> </span>{
<span class="hljs-keyword">this</span><span class="hljs-preprocessor">.port = port<span class="hljs-comment">;
}
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">start</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> Exception </span>{
EventLoopGroup bossGroup = <span class="hljs-keyword">new</span> NioEventLoopGroup()<span class="hljs-comment">;
EventLoopGroup group = <span class="hljs-keyword">new</span> NioEventLoopGroup()<span class="hljs-comment">;
<span class="hljs-keyword">try</span> {
ServerBootstrap sb = <span class="hljs-keyword">new</span> ServerBootstrap()<span class="hljs-comment">;
sb<span class="hljs-preprocessor">.option(ChannelOption<span class="hljs-preprocessor">.SO_BACKLOG, <span class="hljs-number"><span class="hljs-number">1024</span>)<span class="hljs-comment">;
sb<span class="hljs-preprocessor">.group(group, bossGroup) <span class="hljs-comment">// 绑定线程池</span>
<span class="hljs-preprocessor">.channel(NioServerSocketChannel<span class="hljs-preprocessor">.class) <span class="hljs-comment">// 指定使用的channel</span>
<span class="hljs-preprocessor">.localAddress(<span class="hljs-keyword">this</span><span class="hljs-preprocessor">.port)<span class="hljs-comment">// 绑定监听端口</span>
<span class="hljs-preprocessor">.childHandler(<span class="hljs-keyword">new</span> ChannelInitializer<SocketChannel>() { <span class="hljs-comment">// 绑定客户端连接时候触发操作</span>
<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">initChannel</span><span class="hljs-params">(SocketChannel ch)</span> <span class="hljs-keyword">throws</span> Exception </span>{
System<span class="hljs-preprocessor">.out<span class="hljs-preprocessor">.println(<span class="hljs-string"><span class="hljs-string">"报告"</span>)<span class="hljs-comment">;
System<span class="hljs-preprocessor">.out<span class="hljs-preprocessor">.println(<span class="hljs-string"><span class="hljs-string">"信息:有一客户端链接到本服务端"</span>)<span class="hljs-comment">;
System<span class="hljs-preprocessor">.out<span class="hljs-preprocessor">.println(<span class="hljs-string"><span class="hljs-string">"IP:"</span> + ch<span class="hljs-preprocessor">.localAddress()<span class="hljs-preprocessor">.getHostName())<span class="hljs-comment">;
System<span class="hljs-preprocessor">.out<span class="hljs-preprocessor">.println(<span class="hljs-string"><span class="hljs-string">"Port:"</span> + ch<span class="hljs-preprocessor">.localAddress()<span class="hljs-preprocessor">.getPort())<span class="hljs-comment">;
System<span class="hljs-preprocessor">.out<span class="hljs-preprocessor">.println(<span class="hljs-string"><span class="hljs-string">"报告完毕"</span>)<span class="hljs-comment">;
ch<span class="hljs-preprocessor">.pipeline()<span class="hljs-preprocessor">.addLast(<span class="hljs-keyword">new</span> StringEncoder(Charset<span class="hljs-preprocessor">.forName(<span class="hljs-string"><span class="hljs-string">"GBK"</span>)))<span class="hljs-comment">;
ch<span class="hljs-preprocessor">.pipeline()<span class="hljs-preprocessor">.addLast(<span class="hljs-keyword">new</span> EchoServerHandler())<span class="hljs-comment">; <span class="hljs-comment">// 客户端触发操作</span>
ch<span class="hljs-preprocessor">.pipeline()<span class="hljs-preprocessor">.addLast(<span class="hljs-keyword">new</span> ByteArrayEncoder())<span class="hljs-comment">;
}
})<span class="hljs-comment">;
ChannelFuture cf = sb<span class="hljs-preprocessor">.bind()<span class="hljs-preprocessor">.sync()<span class="hljs-comment">; <span class="hljs-comment">// 服务器异步创建绑定</span>
System<span class="hljs-preprocessor">.out<span class="hljs-preprocessor">.println(EchoServer<span class="hljs-preprocessor">.class + <span class="hljs-string"><span class="hljs-string">" 启动正在监听: "</span> + cf<span class="hljs-preprocessor">.channel()<span class="hljs-preprocessor">.localAddress())<span class="hljs-comment">;
cf<span class="hljs-preprocessor">.channel()<span class="hljs-preprocessor">.closeFuture()<span class="hljs-preprocessor">.sync()<span class="hljs-comment">; <span class="hljs-comment">// 关闭服务器通道</span>
} <span class="hljs-keyword">finally</span> {
group<span class="hljs-preprocessor">.shutdownGracefully()<span class="hljs-preprocessor">.sync()<span class="hljs-comment">; <span class="hljs-comment">// 释放线程池资源</span>
bossGroup<span class="hljs-preprocessor">.shutdownGracefully()<span class="hljs-preprocessor">.sync()<span class="hljs-comment">;
}
}
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> Exception </span>{
<span class="hljs-keyword">new</span> EchoServer(<span class="hljs-number"><span class="hljs-number">8888</span>)<span class="hljs-preprocessor">.start()<span class="hljs-comment">; <span class="hljs-comment">// 启动</span>
}
}
EchoServerHandler.java
package Server;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Date;import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;public class EchoServerHandler extends ChannelInboundHandlerAdapter {
<span class="hljs-comment"><span class="hljs-comment">/*
* channelAction
*
* channel 通道 action 活跃的
*
* 当客户端主动链接服务端的链接后,这个通道就是活跃的了。也就是客户端与服务端建立了通信通道并且可以传输数据
*
*/</span>
<span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">void</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">channelActive</span><span class="hljs-params">(ChannelHandlerContext ctx)</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">throws</span> Exception </span>{
System.out.println(ctx.channel().localAddress().toString() + <span class="hljs-string"><span class="hljs-string">" 通道已激活!"</span>);
}
<span class="hljs-comment"><span class="hljs-comment">/*
* channelInactive
*
* channel 通道 Inactive 不活跃的
*
* 当客户端主动断开服务端的链接后,这个通道就是不活跃的。也就是说客户端与服务端的关闭了通信通道并且不可以传输数据
*
*/</span>
<span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">void</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">channelInactive</span><span class="hljs-params">(ChannelHandlerContext ctx)</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">throws</span> Exception </span>{
System.out.println(ctx.channel().localAddress().toString() + <span class="hljs-string"><span class="hljs-string">" 通道不活跃!"</span>);
<span class="hljs-comment"><span class="hljs-comment">// 关闭流</span>
}
<span class="hljs-javadoc"><span class="hljs-comment">/**
*
*</span><span class="hljs-javadoctag"><span class="hljs-comment"> <span class="hljs-doctag">@author</span> Taowd
* TODO 此处用来处理收到的数据中含有中文的时 出现乱码的问题
* 2017年8月31日 下午7:57:28
*</span><span class="hljs-javadoctag"><span class="hljs-comment"> <span class="hljs-doctag">@param</span> buf
*</span><span class="hljs-javadoctag"><span class="hljs-comment"> <span class="hljs-doctag">@return</span>
*/</span>
<span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">private</span> String </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">getMessage</span><span class="hljs-params">(ByteBuf buf)</span> </span>{
<span class="hljs-keyword"><span class="hljs-keyword">byte</span>[] con = <span class="hljs-keyword"><span class="hljs-keyword">new</span> <span class="hljs-keyword"><span class="hljs-keyword">byte</span>[buf.readableBytes()];
buf.readBytes(con);
<span class="hljs-keyword"><span class="hljs-keyword">try</span> {
<span class="hljs-keyword"><span class="hljs-keyword">return</span> <span class="hljs-keyword"><span class="hljs-keyword">new</span> String(con, <span class="hljs-string"><span class="hljs-string">"UTF-8"</span>);
} <span class="hljs-keyword"><span class="hljs-keyword">catch</span> (UnsupportedEncodingException e) {
e.printStackTrace();
<span class="hljs-keyword"><span class="hljs-keyword">return</span> <span class="hljs-keyword"><span class="hljs-keyword">null</span>;
}
}
<span class="hljs-javadoc"><span class="hljs-comment">/**
* 功能:读取服务器发送过来的信息
*/</span>
<span class="hljs-annotation"><span class="hljs-meta">@Override</span>
<span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">void</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">channelRead</span><span class="hljs-params">(ChannelHandlerContext ctx, Object msg)</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">throws</span> Exception </span>{
<span class="hljs-comment"><span class="hljs-comment">// 第一种:接收字符串时的处理</span>
ByteBuf buf = (ByteBuf) msg;
String rev = getMessage(buf);
System.out.println(<span class="hljs-string"><span class="hljs-string">"客户端收到服务器数据:"</span> + rev);
}
<span class="hljs-javadoc"><span class="hljs-comment">/**
* 功能:读取完毕客户端发送过来的数据之后的操作
*/</span>
<span class="hljs-annotation"><span class="hljs-meta">@Override</span>
<span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">void</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">channelReadComplete</span><span class="hljs-params">(ChannelHandlerContext ctx)</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">throws</span> Exception </span>{
System.out.println(<span class="hljs-string"><span class="hljs-string">"服务端接收数据完毕.."</span>);
<span class="hljs-comment"><span class="hljs-comment">// 第一种方法:写一个空的buf,并刷新写出区域。完成后关闭sock channel连接。</span>
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
<span class="hljs-comment"><span class="hljs-comment">// ctx.flush();</span>
<span class="hljs-comment"><span class="hljs-comment">// ctx.flush(); //</span>
<span class="hljs-comment"><span class="hljs-comment">// 第二种方法:在client端关闭channel连接,这样的话,会触发两次channelReadComplete方法。</span>
<span class="hljs-comment"><span class="hljs-comment">// ctx.flush().close().sync(); // 第三种:改成这种写法也可以,但是这中写法,没有第一种方法的好。</span>
}
<span class="hljs-javadoc"><span class="hljs-comment">/**
* 功能:服务端发生异常的操作
*/</span>
<span class="hljs-annotation"><span class="hljs-meta">@Override</span>
<span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">void</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">exceptionCaught</span><span class="hljs-params">(ChannelHandlerContext ctx, Throwable cause)</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">throws</span> Exception </span>{
ctx.close();
System.out.println(<span class="hljs-string"><span class="hljs-string">"异常信息:\r\n"</span> + cause.getMessage());
}
}
客户端代码
EchoClient.java
package Cilent;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
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.bytes.ByteArrayEncoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.stream.ChunkedWriteHandler;public class EchoClient {
private final String host;
private final int port;<span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">EchoClient</span><span class="hljs-params">()</span> </span>{
<span class="hljs-keyword"><span class="hljs-keyword">this</span>(<span class="hljs-number"><span class="hljs-number">0</span>);
}
<span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">EchoClient</span><span class="hljs-params">(</span></span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-params"><span class="hljs-keyword">int</span> port)</span> </span>{
<span class="hljs-keyword"><span class="hljs-keyword">this</span>(<span class="hljs-string"><span class="hljs-string">"localhost"</span>, port);
}
<span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">EchoClient</span><span class="hljs-params">(String host, </span></span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-params"><span class="hljs-keyword">int</span> port)</span> </span>{
<span class="hljs-keyword"><span class="hljs-keyword">this</span>.host = host;
<span class="hljs-keyword"><span class="hljs-keyword">this</span>.port = port;
}
<span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">void</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">start</span><span class="hljs-params">()</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">throws</span> Exception </span>{
EventLoopGroup group = <span class="hljs-keyword"><span class="hljs-keyword">new</span> NioEventLoopGroup();
<span class="hljs-keyword"><span class="hljs-keyword">try</span> {
Bootstrap b = <span class="hljs-keyword"><span class="hljs-keyword">new</span> Bootstrap();
b.group(group) <span class="hljs-comment"><span class="hljs-comment">// 注册线程池</span>
.channel(NioSocketChannel.class) <span class="hljs-comment"><span class="hljs-comment">// 使用NioSocketChannel来作为连接用的channel类</span>
.remoteAddress(<span class="hljs-keyword"><span class="hljs-keyword">new</span> InetSocketAddress(<span class="hljs-keyword"><span class="hljs-keyword">this</span>.host, <span class="hljs-keyword"><span class="hljs-keyword">this</span>.port)) <span class="hljs-comment"><span class="hljs-comment">// 绑定连接端口和host信息</span>
.handler(<span class="hljs-keyword"><span class="hljs-keyword">new</span> ChannelInitializer<SocketChannel>() { <span class="hljs-comment"><span class="hljs-comment">// 绑定连接初始化器</span>
<span class="hljs-annotation"><span class="hljs-meta">@Override</span>
<span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">protected</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">void</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">initChannel</span><span class="hljs-params">(SocketChannel ch)</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">throws</span> Exception </span>{
System.out.println(<span class="hljs-string"><span class="hljs-string">"正在连接中..."</span>);
ch.pipeline().addLast(<span class="hljs-keyword"><span class="hljs-keyword">new</span> StringEncoder(Charset.forName(<span class="hljs-string"><span class="hljs-string">"GBK"</span>)));
ch.pipeline().addLast(<span class="hljs-keyword"><span class="hljs-keyword">new</span> EchoClientHandler());
ch.pipeline().addLast(<span class="hljs-keyword"><span class="hljs-keyword">new</span> ByteArrayEncoder());
ch.pipeline().addLast(<span class="hljs-keyword"><span class="hljs-keyword">new</span> ChunkedWriteHandler());
}
});
<span class="hljs-comment"><span class="hljs-comment">// System.out.println("服务端连接成功..");</span>
ChannelFuture cf = b.connect().sync(); <span class="hljs-comment"><span class="hljs-comment">// 异步连接服务器</span>
System.out.println(<span class="hljs-string"><span class="hljs-string">"服务端连接成功..."</span>); <span class="hljs-comment"><span class="hljs-comment">// 连接完成</span>
cf.channel().closeFuture().sync(); <span class="hljs-comment"><span class="hljs-comment">// 异步等待关闭连接channel</span>
System.out.println(<span class="hljs-string"><span class="hljs-string">"连接已关闭.."</span>); <span class="hljs-comment"><span class="hljs-comment">// 关闭完成</span>
} <span class="hljs-keyword"><span class="hljs-keyword">finally</span> {
group.shutdownGracefully().sync(); <span class="hljs-comment"><span class="hljs-comment">// 释放线程池资源</span>
}
}
<span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">static</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">void</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">throws</span> Exception </span>{
<span class="hljs-keyword"><span class="hljs-keyword">new</span> EchoClient(<span class="hljs-string"><span class="hljs-string">"127.0.0.1"</span>, <span class="hljs-number"><span class="hljs-number">8888</span>).start(); <span class="hljs-comment"><span class="hljs-comment">// 连接127.0.0.1/65535,并启动</span>
}
}
EchoClientHandler.java
package Cilent;
import java.nio.charset.Charset;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.CharsetUtil;public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
<span class="hljs-javadoc"><span class="hljs-comment">/**
* 向服务端发送数据
*/</span>
<span class="hljs-annotation"><span class="hljs-meta">@Override</span>
public void channelActive(<span class="hljs-type">ChannelHandlerContext</span> ctx) <span class="hljs-keyword"><span class="hljs-keyword">throws</span> <span class="hljs-type">Exception</span> {
<span class="hljs-type">System</span>.out.println(<span class="hljs-string"><span class="hljs-string">"客户端与服务端通道-开启:"</span> + ctx.channel().localAddress() + <span class="hljs-string"><span class="hljs-string">"channelActive"</span>);
<span class="hljs-type">String</span> sendInfo = <span class="hljs-string"><span class="hljs-string">"Hello 这里是客户端 你好啊!"</span>;
<span class="hljs-type">System</span>.out.println(<span class="hljs-string"><span class="hljs-string">"客户端准备发送的数据包:"</span> + sendInfo);
ctx.writeAndFlush(<span class="hljs-type">Unpooled</span>.copiedBuffer(sendInfo, <span class="hljs-type">CharsetUtil</span>.<span class="hljs-type">UTF_8</span>)); <span class="hljs-comment"><span class="hljs-comment">// 必须有flush</span>
}
<span class="hljs-javadoc"><span class="hljs-comment">/**
* channelInactive
*
* channel 通道 Inactive 不活跃的
*
* 当客户端主动断开服务端的链接后,这个通道就是不活跃的。也就是说客户端与服务端的关闭了通信通道并且不可以传输数据
*
*/</span>
public void channelInactive(<span class="hljs-type">ChannelHandlerContext</span> ctx) <span class="hljs-keyword"><span class="hljs-keyword">throws</span> <span class="hljs-type">Exception</span> {
<span class="hljs-type">System</span>.out.println(<span class="hljs-string"><span class="hljs-string">"客户端与服务端通道-关闭:"</span> + ctx.channel().localAddress() + <span class="hljs-string"><span class="hljs-string">"channelInactive"</span>);
}
<span class="hljs-annotation"><span class="hljs-meta">@Override</span>
<span class="hljs-keyword"><span class="hljs-keyword">protected</span> void channelRead0(<span class="hljs-type">ChannelHandlerContext</span> ctx, <span class="hljs-type">ByteBuf</span> msg) <span class="hljs-keyword"><span class="hljs-keyword">throws</span> <span class="hljs-type">Exception</span> {
<span class="hljs-type">System</span>.out.println(<span class="hljs-string"><span class="hljs-string">"读取客户端通道信息.."</span>);
<span class="hljs-type">ByteBuf</span> buf = msg.readBytes(msg.readableBytes());
<span class="hljs-type">System</span>.out.println(
<span class="hljs-string"><span class="hljs-string">"客户端接收到的服务端信息:"</span> + <span class="hljs-type">ByteBufUtil</span>.hexDump(buf) + <span class="hljs-string"><span class="hljs-string">"; 数据包为:"</span> + buf.toString(<span class="hljs-type">Charset</span>.forName(<span class="hljs-string"><span class="hljs-string">"utf-8"</span>)));
}
<span class="hljs-annotation"><span class="hljs-meta">@Override</span>
public void exceptionCaught(<span class="hljs-type">ChannelHandlerContext</span> ctx, <span class="hljs-type">Throwable</span> cause) <span class="hljs-keyword"><span class="hljs-keyword">throws</span> <span class="hljs-type">Exception</span> {
ctx.close();
<span class="hljs-type">System</span>.out.println(<span class="hljs-string"><span class="hljs-string">"异常退出:"</span> + cause.getMessage());
}
}
执行结果图
原文地址:https://www.cnblogs.com/jtlgb/p/8757587.html
Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。
也就是说,Netty 是一个基于NIO的客户、服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用。Netty相当简化和流线化了网络应用的编程开发过程,例如,TCP和UDP的socket服务开发。
“快速”和“简单”并不用产生维护性或性能上的问题。Netty 是一个吸收了多种协议的实现经验,这些协议包括FTP,SMTP,HTTP,各种二进制,文本协议,并经过相当精心设计的项目,最终,Netty 成功的找到了一种方式,在保证易于开发的同时还保证了其应用的性能,稳定性和伸缩性。
本文的目的
使用Netty实现一个Socket通讯,包括客户端和服务端,通过服务端进行监听,客户端发送信息,服务端可进行接收,并进行返回数据,完成一个完整的通讯。
工程结构
POM文件配置
<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.taowd.socket</groupId>
<artifactId>SocketDemo2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.6.Final</version>
</dependency>
</dependencies>
</project>
服务端代码
EchoServer.java
package Server;
import java.nio.charset.Charset;
import io.netty.bootstrap.ServerBootstrap;
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.NioServerSocketChannel;
import io.netty.handler.codec.bytes.ByteArrayEncoder;
import io.netty.handler.codec.string.StringEncoder;public class EchoServer {
private final int port;<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">EchoServer</span><span class="hljs-params">(<span class="hljs-keyword">int</span> port)</span> </span>{
<span class="hljs-keyword">this</span><span class="hljs-preprocessor">.port = port<span class="hljs-comment">;
}
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">start</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> Exception </span>{
EventLoopGroup bossGroup = <span class="hljs-keyword">new</span> NioEventLoopGroup()<span class="hljs-comment">;
EventLoopGroup group = <span class="hljs-keyword">new</span> NioEventLoopGroup()<span class="hljs-comment">;
<span class="hljs-keyword">try</span> {
ServerBootstrap sb = <span class="hljs-keyword">new</span> ServerBootstrap()<span class="hljs-comment">;
sb<span class="hljs-preprocessor">.option(ChannelOption<span class="hljs-preprocessor">.SO_BACKLOG, <span class="hljs-number"><span class="hljs-number">1024</span>)<span class="hljs-comment">;
sb<span class="hljs-preprocessor">.group(group, bossGroup) <span class="hljs-comment">// 绑定线程池</span>
<span class="hljs-preprocessor">.channel(NioServerSocketChannel<span class="hljs-preprocessor">.class) <span class="hljs-comment">// 指定使用的channel</span>
<span class="hljs-preprocessor">.localAddress(<span class="hljs-keyword">this</span><span class="hljs-preprocessor">.port)<span class="hljs-comment">// 绑定监听端口</span>
<span class="hljs-preprocessor">.childHandler(<span class="hljs-keyword">new</span> ChannelInitializer<SocketChannel>() { <span class="hljs-comment">// 绑定客户端连接时候触发操作</span>
<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">initChannel</span><span class="hljs-params">(SocketChannel ch)</span> <span class="hljs-keyword">throws</span> Exception </span>{
System<span class="hljs-preprocessor">.out<span class="hljs-preprocessor">.println(<span class="hljs-string"><span class="hljs-string">"报告"</span>)<span class="hljs-comment">;
System<span class="hljs-preprocessor">.out<span class="hljs-preprocessor">.println(<span class="hljs-string"><span class="hljs-string">"信息:有一客户端链接到本服务端"</span>)<span class="hljs-comment">;
System<span class="hljs-preprocessor">.out<span class="hljs-preprocessor">.println(<span class="hljs-string"><span class="hljs-string">"IP:"</span> + ch<span class="hljs-preprocessor">.localAddress()<span class="hljs-preprocessor">.getHostName())<span class="hljs-comment">;
System<span class="hljs-preprocessor">.out<span class="hljs-preprocessor">.println(<span class="hljs-string"><span class="hljs-string">"Port:"</span> + ch<span class="hljs-preprocessor">.localAddress()<span class="hljs-preprocessor">.getPort())<span class="hljs-comment">;
System<span class="hljs-preprocessor">.out<span class="hljs-preprocessor">.println(<span class="hljs-string"><span class="hljs-string">"报告完毕"</span>)<span class="hljs-comment">;
ch<span class="hljs-preprocessor">.pipeline()<span class="hljs-preprocessor">.addLast(<span class="hljs-keyword">new</span> StringEncoder(Charset<span class="hljs-preprocessor">.forName(<span class="hljs-string"><span class="hljs-string">"GBK"</span>)))<span class="hljs-comment">;
ch<span class="hljs-preprocessor">.pipeline()<span class="hljs-preprocessor">.addLast(<span class="hljs-keyword">new</span> EchoServerHandler())<span class="hljs-comment">; <span class="hljs-comment">// 客户端触发操作</span>
ch<span class="hljs-preprocessor">.pipeline()<span class="hljs-preprocessor">.addLast(<span class="hljs-keyword">new</span> ByteArrayEncoder())<span class="hljs-comment">;
}
})<span class="hljs-comment">;
ChannelFuture cf = sb<span class="hljs-preprocessor">.bind()<span class="hljs-preprocessor">.sync()<span class="hljs-comment">; <span class="hljs-comment">// 服务器异步创建绑定</span>
System<span class="hljs-preprocessor">.out<span class="hljs-preprocessor">.println(EchoServer<span class="hljs-preprocessor">.class + <span class="hljs-string"><span class="hljs-string">" 启动正在监听: "</span> + cf<span class="hljs-preprocessor">.channel()<span class="hljs-preprocessor">.localAddress())<span class="hljs-comment">;
cf<span class="hljs-preprocessor">.channel()<span class="hljs-preprocessor">.closeFuture()<span class="hljs-preprocessor">.sync()<span class="hljs-comment">; <span class="hljs-comment">// 关闭服务器通道</span>
} <span class="hljs-keyword">finally</span> {
group<span class="hljs-preprocessor">.shutdownGracefully()<span class="hljs-preprocessor">.sync()<span class="hljs-comment">; <span class="hljs-comment">// 释放线程池资源</span>
bossGroup<span class="hljs-preprocessor">.shutdownGracefully()<span class="hljs-preprocessor">.sync()<span class="hljs-comment">;
}
}
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> Exception </span>{
<span class="hljs-keyword">new</span> EchoServer(<span class="hljs-number"><span class="hljs-number">8888</span>)<span class="hljs-preprocessor">.start()<span class="hljs-comment">; <span class="hljs-comment">// 启动</span>
}
}
EchoServerHandler.java
package Server;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Date;import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;public class EchoServerHandler extends ChannelInboundHandlerAdapter {
<span class="hljs-comment"><span class="hljs-comment">/*
* channelAction
*
* channel 通道 action 活跃的
*
* 当客户端主动链接服务端的链接后,这个通道就是活跃的了。也就是客户端与服务端建立了通信通道并且可以传输数据
*
*/</span>
<span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">void</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">channelActive</span><span class="hljs-params">(ChannelHandlerContext ctx)</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">throws</span> Exception </span>{
System.out.println(ctx.channel().localAddress().toString() + <span class="hljs-string"><span class="hljs-string">" 通道已激活!"</span>);
}
<span class="hljs-comment"><span class="hljs-comment">/*
* channelInactive
*
* channel 通道 Inactive 不活跃的
*
* 当客户端主动断开服务端的链接后,这个通道就是不活跃的。也就是说客户端与服务端的关闭了通信通道并且不可以传输数据
*
*/</span>
<span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">void</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">channelInactive</span><span class="hljs-params">(ChannelHandlerContext ctx)</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">throws</span> Exception </span>{
System.out.println(ctx.channel().localAddress().toString() + <span class="hljs-string"><span class="hljs-string">" 通道不活跃!"</span>);
<span class="hljs-comment"><span class="hljs-comment">// 关闭流</span>
}
<span class="hljs-javadoc"><span class="hljs-comment">/**
*
*</span><span class="hljs-javadoctag"><span class="hljs-comment"> <span class="hljs-doctag">@author</span> Taowd
* TODO 此处用来处理收到的数据中含有中文的时 出现乱码的问题
* 2017年8月31日 下午7:57:28
*</span><span class="hljs-javadoctag"><span class="hljs-comment"> <span class="hljs-doctag">@param</span> buf
*</span><span class="hljs-javadoctag"><span class="hljs-comment"> <span class="hljs-doctag">@return</span>
*/</span>
<span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">private</span> String </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">getMessage</span><span class="hljs-params">(ByteBuf buf)</span> </span>{
<span class="hljs-keyword"><span class="hljs-keyword">byte</span>[] con = <span class="hljs-keyword"><span class="hljs-keyword">new</span> <span class="hljs-keyword"><span class="hljs-keyword">byte</span>[buf.readableBytes()];
buf.readBytes(con);
<span class="hljs-keyword"><span class="hljs-keyword">try</span> {
<span class="hljs-keyword"><span class="hljs-keyword">return</span> <span class="hljs-keyword"><span class="hljs-keyword">new</span> String(con, <span class="hljs-string"><span class="hljs-string">"UTF-8"</span>);
} <span class="hljs-keyword"><span class="hljs-keyword">catch</span> (UnsupportedEncodingException e) {
e.printStackTrace();
<span class="hljs-keyword"><span class="hljs-keyword">return</span> <span class="hljs-keyword"><span class="hljs-keyword">null</span>;
}
}
<span class="hljs-javadoc"><span class="hljs-comment">/**
* 功能:读取服务器发送过来的信息
*/</span>
<span class="hljs-annotation"><span class="hljs-meta">@Override</span>
<span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">void</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">channelRead</span><span class="hljs-params">(ChannelHandlerContext ctx, Object msg)</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">throws</span> Exception </span>{
<span class="hljs-comment"><span class="hljs-comment">// 第一种:接收字符串时的处理</span>
ByteBuf buf = (ByteBuf) msg;
String rev = getMessage(buf);
System.out.println(<span class="hljs-string"><span class="hljs-string">"客户端收到服务器数据:"</span> + rev);
}
<span class="hljs-javadoc"><span class="hljs-comment">/**
* 功能:读取完毕客户端发送过来的数据之后的操作
*/</span>
<span class="hljs-annotation"><span class="hljs-meta">@Override</span>
<span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">void</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">channelReadComplete</span><span class="hljs-params">(ChannelHandlerContext ctx)</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">throws</span> Exception </span>{
System.out.println(<span class="hljs-string"><span class="hljs-string">"服务端接收数据完毕.."</span>);
<span class="hljs-comment"><span class="hljs-comment">// 第一种方法:写一个空的buf,并刷新写出区域。完成后关闭sock channel连接。</span>
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
<span class="hljs-comment"><span class="hljs-comment">// ctx.flush();</span>
<span class="hljs-comment"><span class="hljs-comment">// ctx.flush(); //</span>
<span class="hljs-comment"><span class="hljs-comment">// 第二种方法:在client端关闭channel连接,这样的话,会触发两次channelReadComplete方法。</span>
<span class="hljs-comment"><span class="hljs-comment">// ctx.flush().close().sync(); // 第三种:改成这种写法也可以,但是这中写法,没有第一种方法的好。</span>
}
<span class="hljs-javadoc"><span class="hljs-comment">/**
* 功能:服务端发生异常的操作
*/</span>
<span class="hljs-annotation"><span class="hljs-meta">@Override</span>
<span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">void</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">exceptionCaught</span><span class="hljs-params">(ChannelHandlerContext ctx, Throwable cause)</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">throws</span> Exception </span>{
ctx.close();
System.out.println(<span class="hljs-string"><span class="hljs-string">"异常信息:\r\n"</span> + cause.getMessage());
}
}
客户端代码
EchoClient.java
package Cilent;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
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.bytes.ByteArrayEncoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.stream.ChunkedWriteHandler;public class EchoClient {
private final String host;
private final int port;<span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">EchoClient</span><span class="hljs-params">()</span> </span>{
<span class="hljs-keyword"><span class="hljs-keyword">this</span>(<span class="hljs-number"><span class="hljs-number">0</span>);
}
<span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">EchoClient</span><span class="hljs-params">(</span></span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-params"><span class="hljs-keyword">int</span> port)</span> </span>{
<span class="hljs-keyword"><span class="hljs-keyword">this</span>(<span class="hljs-string"><span class="hljs-string">"localhost"</span>, port);
}
<span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">EchoClient</span><span class="hljs-params">(String host, </span></span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-params"><span class="hljs-keyword">int</span> port)</span> </span>{
<span class="hljs-keyword"><span class="hljs-keyword">this</span>.host = host;
<span class="hljs-keyword"><span class="hljs-keyword">this</span>.port = port;
}
<span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">void</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">start</span><span class="hljs-params">()</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">throws</span> Exception </span>{
EventLoopGroup group = <span class="hljs-keyword"><span class="hljs-keyword">new</span> NioEventLoopGroup();
<span class="hljs-keyword"><span class="hljs-keyword">try</span> {
Bootstrap b = <span class="hljs-keyword"><span class="hljs-keyword">new</span> Bootstrap();
b.group(group) <span class="hljs-comment"><span class="hljs-comment">// 注册线程池</span>
.channel(NioSocketChannel.class) <span class="hljs-comment"><span class="hljs-comment">// 使用NioSocketChannel来作为连接用的channel类</span>
.remoteAddress(<span class="hljs-keyword"><span class="hljs-keyword">new</span> InetSocketAddress(<span class="hljs-keyword"><span class="hljs-keyword">this</span>.host, <span class="hljs-keyword"><span class="hljs-keyword">this</span>.port)) <span class="hljs-comment"><span class="hljs-comment">// 绑定连接端口和host信息</span>
.handler(<span class="hljs-keyword"><span class="hljs-keyword">new</span> ChannelInitializer<SocketChannel>() { <span class="hljs-comment"><span class="hljs-comment">// 绑定连接初始化器</span>
<span class="hljs-annotation"><span class="hljs-meta">@Override</span>
<span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">protected</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">void</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">initChannel</span><span class="hljs-params">(SocketChannel ch)</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">throws</span> Exception </span>{
System.out.println(<span class="hljs-string"><span class="hljs-string">"正在连接中..."</span>);
ch.pipeline().addLast(<span class="hljs-keyword"><span class="hljs-keyword">new</span> StringEncoder(Charset.forName(<span class="hljs-string"><span class="hljs-string">"GBK"</span>)));
ch.pipeline().addLast(<span class="hljs-keyword"><span class="hljs-keyword">new</span> EchoClientHandler());
ch.pipeline().addLast(<span class="hljs-keyword"><span class="hljs-keyword">new</span> ByteArrayEncoder());
ch.pipeline().addLast(<span class="hljs-keyword"><span class="hljs-keyword">new</span> ChunkedWriteHandler());
}
});
<span class="hljs-comment"><span class="hljs-comment">// System.out.println("服务端连接成功..");</span>
ChannelFuture cf = b.connect().sync(); <span class="hljs-comment"><span class="hljs-comment">// 异步连接服务器</span>
System.out.println(<span class="hljs-string"><span class="hljs-string">"服务端连接成功..."</span>); <span class="hljs-comment"><span class="hljs-comment">// 连接完成</span>
cf.channel().closeFuture().sync(); <span class="hljs-comment"><span class="hljs-comment">// 异步等待关闭连接channel</span>
System.out.println(<span class="hljs-string"><span class="hljs-string">"连接已关闭.."</span>); <span class="hljs-comment"><span class="hljs-comment">// 关闭完成</span>
} <span class="hljs-keyword"><span class="hljs-keyword">finally</span> {
group.shutdownGracefully().sync(); <span class="hljs-comment"><span class="hljs-comment">// 释放线程池资源</span>
}
}
<span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">static</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">void</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">throws</span> Exception </span>{
<span class="hljs-keyword"><span class="hljs-keyword">new</span> EchoClient(<span class="hljs-string"><span class="hljs-string">"127.0.0.1"</span>, <span class="hljs-number"><span class="hljs-number">8888</span>).start(); <span class="hljs-comment"><span class="hljs-comment">// 连接127.0.0.1/65535,并启动</span>
}
}
EchoClientHandler.java
package Cilent;
import java.nio.charset.Charset;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.CharsetUtil;public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
<span class="hljs-javadoc"><span class="hljs-comment">/**
* 向服务端发送数据
*/</span>
<span class="hljs-annotation"><span class="hljs-meta">@Override</span>
public void channelActive(<span class="hljs-type">ChannelHandlerContext</span> ctx) <span class="hljs-keyword"><span class="hljs-keyword">throws</span> <span class="hljs-type">Exception</span> {
<span class="hljs-type">System</span>.out.println(<span class="hljs-string"><span class="hljs-string">"客户端与服务端通道-开启:"</span> + ctx.channel().localAddress() + <span class="hljs-string"><span class="hljs-string">"channelActive"</span>);
<span class="hljs-type">String</span> sendInfo = <span class="hljs-string"><span class="hljs-string">"Hello 这里是客户端 你好啊!"</span>;
<span class="hljs-type">System</span>.out.println(<span class="hljs-string"><span class="hljs-string">"客户端准备发送的数据包:"</span> + sendInfo);
ctx.writeAndFlush(<span class="hljs-type">Unpooled</span>.copiedBuffer(sendInfo, <span class="hljs-type">CharsetUtil</span>.<span class="hljs-type">UTF_8</span>)); <span class="hljs-comment"><span class="hljs-comment">// 必须有flush</span>
}
<span class="hljs-javadoc"><span class="hljs-comment">/**
* channelInactive
*
* channel 通道 Inactive 不活跃的
*
* 当客户端主动断开服务端的链接后,这个通道就是不活跃的。也就是说客户端与服务端的关闭了通信通道并且不可以传输数据
*
*/</span>
public void channelInactive(<span class="hljs-type">ChannelHandlerContext</span> ctx) <span class="hljs-keyword"><span class="hljs-keyword">throws</span> <span class="hljs-type">Exception</span> {
<span class="hljs-type">System</span>.out.println(<span class="hljs-string"><span class="hljs-string">"客户端与服务端通道-关闭:"</span> + ctx.channel().localAddress() + <span class="hljs-string"><span class="hljs-string">"channelInactive"</span>);
}
<span class="hljs-annotation"><span class="hljs-meta">@Override</span>
<span class="hljs-keyword"><span class="hljs-keyword">protected</span> void channelRead0(<span class="hljs-type">ChannelHandlerContext</span> ctx, <span class="hljs-type">ByteBuf</span> msg) <span class="hljs-keyword"><span class="hljs-keyword">throws</span> <span class="hljs-type">Exception</span> {
<span class="hljs-type">System</span>.out.println(<span class="hljs-string"><span class="hljs-string">"读取客户端通道信息.."</span>);
<span class="hljs-type">ByteBuf</span> buf = msg.readBytes(msg.readableBytes());
<span class="hljs-type">System</span>.out.println(
<span class="hljs-string"><span class="hljs-string">"客户端接收到的服务端信息:"</span> + <span class="hljs-type">ByteBufUtil</span>.hexDump(buf) + <span class="hljs-string"><span class="hljs-string">"; 数据包为:"</span> + buf.toString(<span class="hljs-type">Charset</span>.forName(<span class="hljs-string"><span class="hljs-string">"utf-8"</span>)));
}
<span class="hljs-annotation"><span class="hljs-meta">@Override</span>
public void exceptionCaught(<span class="hljs-type">ChannelHandlerContext</span> ctx, <span class="hljs-type">Throwable</span> cause) <span class="hljs-keyword"><span class="hljs-keyword">throws</span> <span class="hljs-type">Exception</span> {
ctx.close();
<span class="hljs-type">System</span>.out.println(<span class="hljs-string"><span class="hljs-string">"异常退出:"</span> + cause.getMessage());
}
}
执行结果图
原文地址:https://www.cnblogs.com/jtlgb/p/8757587.html
以上是 Socket通讯-Netty框架实现Java通讯 的全部内容, 来源链接: utcz.com/z/391752.html