Netty Client和Server端实现
本文基于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端实现的更多相关文章
- 上机题目(0基础)- Java网络操作-Socket实现client和server端通信二(Java)
		上一节实现了client像server端发送请求.本节将实现server端向client回传信息.实现原理非常easy,在原来的基础上.在server端实现输出流,在client实现输入流就可以,详细 ... 
- 上机题目(0基础)- Java网络操作-Socket实现client和server端通信(Java)
		非常多刚開始学习的人对于java网络通信不太熟悉.对相关概念也不太明确,这里我们主要实现一下socket通信,socket通信在java中应用十分广泛.比如QQ和MSN等都是基于socket通信的,什 ... 
- Socket实现client和server端通信(Java)(转)
		转自: https://blog.csdn.net/yayun0516/article/details/50819147 https://www.jianshu.com/p/2d4f223f1462 ... 
- client、server端编程
		首先是从main函数开发: int main(itn argc,char* argv[]) { pthread_t thread; int count; int status; cli ... 
- server端获得到client端的IP地址的格式
		使用telnet,ping或其他client连接server端时,server端获得的client端的ip地址取决于client端使用的时ipv4还是ipv6地址. 例: client IPv4地址: ... 
- 多个client与一个server端通信的问题
		多个client与一个server端通信的问题 上篇博文主要是讲的关于client与server端的通信问题.在上篇博文中当我们仅仅有一个client訪问我们的server时是能够正常执行的,可是当我 ... 
- Linux下的C Socket编程 -- server端的简单示例
		Linux下的C Socket编程(三) server端的简单示例 经过前面的client端的学习,我们已经知道了如何创建socket,所以接下来就是去绑定他到具体的一个端口上面去. 绑定socket ... 
- Android简单的聊天室开发(client与server沟通)
		请尊重他人的劳动成果.转载请注明出处:Android开发之简单的聊天室(client与server进行通信) 1. 预备知识:Tcp/IP协议与Socket TCP/IP 是Transmission ... 
- 使用gRPC搭建Server端与Client端
		gRPC简介 gRPC是一种RPC框架技术,采用Protocal Buffers(协议缓存) 作为其接口定义的语言(就是Proto来写接口)和基础的消息交换格式. 在gRPC中,客户端应用程序可以直接 ... 
随机推荐
- 4.Spark Streaming事务处理
			首先,我们必须知道什么是事务及其一致性? 事务应该具有4个属性:原子性.一致性.隔离性.持久性.这四个属性通常称为ACID特性. 原子性(atomicity).一个事务是一个不可分割的工作单位,事务中 ... 
- 错误:Eclipse老是出现 updating error reports database
			Eclipse 火星版(Mars)一直出现 updating error reports database. Window--->Preferences--->General---> ... 
- 面向对象编程课程(OOP)第二单元总结
			一.设计策略 第一次作业(傻瓜式电梯): 由于是第一次写多线程作业,许多的知识还处在理论阶段,所以第一次作业写得非常的朴实无华.整个程序总共有四个类,Main类负责通过电梯类实例化一个电梯,然后通过w ... 
- angularjs学习笔记1-angular总体简介及其特点
			以前开发(web或者移动端)前端主要使用jQuery+原生js,如果使用某些前端UI框架的话,它自己还可能提供一些API可以使用.而且目前很多UI框架都是基于jQuery的,所以说一下由jQuery跨 ... 
- 关于phonegap的白名单机制
			今天在项目中发现了一个问题,使用phonegap开发的APP默认情况下可以将外部网页加载进入手机APP当中,这是相当危险的,同时也会给人一种APP非native的感觉. 可能遇见的一种情况是有些WiF ... 
- 【分类讨论】【spfa】【BFS】Codeforces Round #416 (Div. 2) D. Vladik and Favorite Game
			那个人第一步肯定要么能向下走,要么能向右走.于是一定可以判断出上下是否对调,或者左右是否对调. 然后他往这个方向再走一走就能发现一定可以再往旁边走,此时就可以判断出另一个方向是否对调. 都判断出来以后 ... 
- Maven打war包时,添加本地jar包
			1.在项目根目录中新建lib文件夹,添加jar包 2.在pom.xml文件中添加dependency <dependency> <groupId>com.oracle</ ... 
- spring boot 添加自定义属性
			1.添加jar compile('org.springframework.boot:spring-boot-configuration-processor:1.2.0.RELEASE') 2.在app ... 
- NHibernate官方文档中文版-框架架构(Architecture)
			总体概览 一个非常高层次的NHibernate架构: 这个图展示了NHibernate使用数据库和配置信息来为应用程序提供持久化服务(和持久化对象). 我们想展示一个更加详细的运行时架构.但是NHib ... 
- http-server 超轻量级web服务器
			有的时候做前端,想要运行一些代码,但是又没有必要使用tomcat或者Apache http server,这个时候一个轻量级的简单的http server就可以搞定了. Http-server是基于n ... 
