本文基于Nett4.0.26.Final版本浅析Client与Server端通讯,先看服务器端:

public class Server {

    public static void run(int port) {
/**Netty创建ServerSocketChannel,默认SelectionKey.OP_ACCEPT*/
EventLoopGroup boss = new NioEventLoopGroup();
EventLoopGroup worker = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(boss, worker)
.channel(NioServerSocketChannel.class) // 设置Channel Type
.option(ChannelOption.SO_BACKLOG, 1024) // 设置Channel属性
.childHandler(new ChannelInitializer<SocketChannel>() { @Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new SimpleChannelHandler());
}
});
/**服务器端绑定监听端口并对Channel进行初始化
* 1-ChannelConfig由ChannelOption初始化
* 2-ChannelPipeline(默认DefaultChannelPipeline)添加ChannelHandler
* 3-注册Channel并添加监听器ChannelFutureListener.CLOSE_ON_FAILURE
* 以异步的方式等待上述操作的完成
* */
ChannelFuture channelFuture = bootstrap.bind(port).sync();
if (channelFuture.isDone()) {
System.out.println(String.format("server bind port %s sucess", port));
}
/**CloseFuture异步方式关闭*/
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
boss.shutdownGracefully();
worker.shutdownGracefully();
}
} public static void main(String []args) {
Server.run(8080);
}
} public class SimpleChannelHandler implements ChannelInboundHandler { private static final Gson GSON = new GsonBuilder().create(); /**
* the method called when new connect come
* */
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
System.out.println(String.format("last channel handler [%s] add", ctx.pipeline().last().getClass().getSimpleName()));
} /**
* the method called when client close connect
* */
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
ctx.disconnect(ctx.newPromise());
ctx.close();
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
} /**
* register port for connect channel
* */
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
String connect = ctx.channel().remoteAddress().toString().substring(1);
System.out.println(String.format("remote connecter address %s", connect));
} @Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { } @Override
public void channelActive(ChannelHandlerContext ctx) throws Exception { } @Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception { } @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Request req = GSON.fromJson(String.valueOf(msg), Request.class);
String json = GSON.toJson(new Response(String.format("server get client status [%s]", req.getStatus()), new Random().nextInt(10)));
ctx.write(json);
} @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
} @Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { } @Override
public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception { } }

服务器端的ChannelHandler的handlerRemoved方法是当客户端关闭链接时该方法被触发,服务器应当关闭当前与客户端的连接,完成TCP的四次挥手过程。

客户端的实现:

public class Client {

	public static void run(String host, int port) {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() { @Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new SimpleClientChannelHandler());
} });
/**客户端向服务器发起连接请求
* 1-ChannelConfig由ChannelOption初始化
* 2-ChannelPipeline(默认DefaultChannelPipeline)添加ChannelHandler
* 3-注册Channel并添加监听器ChannelFutureListener.CLOSE_ON_FAILURE
* 以异步的方式等待上述操作的完成
* */
ChannelFuture channelFuture = bootstrap.connect(host, port).sync();
if (channelFuture.isSuccess()) {
System.out.println(String.format("connect server(%s:%s) sucess", host, port));
}
channelFuture.channel().closeFuture().sync();
System.out.println("client close sucess");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();
}
} public static void main(String []args) {
for (int i = 0 ; i < 3 ; ++i) {
Client.run("127.0.0.1", 8080);
System.out.println();
}
// Client.run("127.0.0.1", 8080);
}
} public class SimpleClientChannelHandler implements ChannelInboundHandler{ private static final Gson GSON = new GsonBuilder().create(); /**
* the method called when client add channel handler(1)
* */
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
ChannelHandler channelHandler = ctx.channel().pipeline().last();
System.out.println("client last channel handle " + channelHandler.getClass().getSimpleName());
} /**
* the method called when server disconnect
* */
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
Channel ch = ctx.channel();
SocketAddress local = ch.localAddress();
SocketAddress remote = ch.remoteAddress();
System.out.println(String.format("server(%s) diconnect and client(%s) close connect", remote.toString().substring(1), local.toString().substring(1)));
ctx.close();
} /**
* the method called for register port before connect server(2)
* */
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("client start to register port");
} @Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { } /**
* the method called when channel active(3)
* */
public void channelActive(ChannelHandlerContext ctx) throws Exception {
String json = GSON.toJson(new Request("client status", new Random().nextInt(10)));
ctx.writeAndFlush(json);
System.out.println(String.format("connect established and send to server message [%s]", json));
} @Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception { } /**
* close after receive response from server(server also should close connect)
* */
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println(String.format("client receive message [%s]", String.valueOf(msg)));
ctx.disconnect(ctx.newPromise());
} @Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
System.out.println("77777");
} @Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
System.out.println("88888");
} @Override
public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
System.out.println("99999");
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
} }

  在客户端的ChannelHandler中有几个关键方法:

channelActive方法:客户端与服务器建立连接且Channel被激活时该方法被调用,本文在客户端与服务器端建立连接就绪时向服务器发送数据

channelRead方法:当服务器端有数据发送时方法被调用,本文在收到服务器端响应时关闭当前连接(此时服务器端的handlerRemoved方法被调用)

handlerRemoved方法:当服务器确认断开连接时该方法被调用,客户端应关闭Channel(TCP四次挥手结束)

Netty Client和Server端实现的更多相关文章

  1. 上机题目(0基础)- Java网络操作-Socket实现client和server端通信二(Java)

    上一节实现了client像server端发送请求.本节将实现server端向client回传信息.实现原理非常easy,在原来的基础上.在server端实现输出流,在client实现输入流就可以,详细 ...

  2. 上机题目(0基础)- Java网络操作-Socket实现client和server端通信(Java)

    非常多刚開始学习的人对于java网络通信不太熟悉.对相关概念也不太明确,这里我们主要实现一下socket通信,socket通信在java中应用十分广泛.比如QQ和MSN等都是基于socket通信的,什 ...

  3. Socket实现client和server端通信(Java)(转)

    转自: https://blog.csdn.net/yayun0516/article/details/50819147 https://www.jianshu.com/p/2d4f223f1462 ...

  4. client、server端编程

    首先是从main函数开发: int main(itn argc,char* argv[]) { pthread_t thread; int count; int status;         cli ...

  5. server端获得到client端的IP地址的格式

    使用telnet,ping或其他client连接server端时,server端获得的client端的ip地址取决于client端使用的时ipv4还是ipv6地址. 例: client IPv4地址: ...

  6. 多个client与一个server端通信的问题

    多个client与一个server端通信的问题 上篇博文主要是讲的关于client与server端的通信问题.在上篇博文中当我们仅仅有一个client訪问我们的server时是能够正常执行的,可是当我 ...

  7. Linux下的C Socket编程 -- server端的简单示例

    Linux下的C Socket编程(三) server端的简单示例 经过前面的client端的学习,我们已经知道了如何创建socket,所以接下来就是去绑定他到具体的一个端口上面去. 绑定socket ...

  8. Android简单的聊天室开发(client与server沟通)

    请尊重他人的劳动成果.转载请注明出处:Android开发之简单的聊天室(client与server进行通信) 1. 预备知识:Tcp/IP协议与Socket TCP/IP 是Transmission ...

  9. 使用gRPC搭建Server端与Client端

    gRPC简介 gRPC是一种RPC框架技术,采用Protocal Buffers(协议缓存) 作为其接口定义的语言(就是Proto来写接口)和基础的消息交换格式. 在gRPC中,客户端应用程序可以直接 ...

随机推荐

  1. es6字符串模板总结

    我们平时用原生js插入标签或者用node.js写数据库语言时候,经常需要大量的字符串进行转义,很容易出错,有了es6的字符串模板,就再也不用担心会出错了 1.模板中的变量写在${}中,${}中的值可以 ...

  2. jQuery筛选

    1.filter筛选出与指定表达式匹配的元素集合 html: <p>Hello</p><p>Hello Again</p><p class=&qu ...

  3. linux 服务器之间文件传送

    linux 服务器之间文件传送免密码输入传递: expect -c " set timeout 10 spawn scp ××××××.tar.bz2 root@172.16.17.34:/ ...

  4. android 内存分哪些区

    韩梦飞沙 yue31313 韩亚飞 han_meng_fei_sha 313134555@qq.com android 内存分哪些区 内存分哪些区 ============ 内存分为的5大区 1.栈区 ...

  5. 【最小生成树】【kruscal】【贪心】CDOJ1636 梦后楼台高锁,酒醒帘幕低垂

    首先,考虑到,我们需要找到一条路径,使它的最小边尽量大,最大边尽量小 然后,考虑到m比较小,我们可以去寻找一个m^2或者m^2logm的算法 考虑枚举最小边,那么我们就需要在m或者mlogm的时间内找 ...

  6. nginx和php-fpm的用户权限

    启动php-fpm sudo php-fpm -c /etc/php.ini [17-Sep-2018 00:36:59] ERROR: [pool www] please specify user ...

  7. codevs 1966 乘法游戏

    1966 乘法游戏  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题目描述 Description 乘法游戏是在一行牌上进行的.每一张牌包括了一个正整数.在每 ...

  8. Codeforces Gym 100269F Flight Boarding Optimization 树状数组维护dp

    Flight Boarding Optimization 题目连接: http://codeforces.com/gym/100269/attachments Description Peter is ...

  9. Jenkins用HTTP Request Plugin插件进行网站的监控/加探针(运维监控)

    使用的插件: [HTTP Request Plugin] 思路: 说明:只能是网站是否正常打开,而不能是这个网站业务是否正常,如果是后者,则需要写特定的接口进行请求处理. 1.通过插件,发送GET请求 ...

  10. jstack_查看当前进程及所属线程执行情况

    C:\Program Files\Java\jdk1.7.0_45\bin\jstack.exe   1.任务管理器:进程选择PID   2.命令行执行        cd C:\Program Fi ...