Socket通讯-Netty框架实现Java通讯

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&lt;SocketChannel&gt;() { <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&lt;SocketChannel&gt;() { <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&lt;SocketChannel&gt;() { <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&lt;SocketChannel&gt;() { <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

回到顶部