为什么80%的码农都做不了架构师?>>>
最近在学习netty,看了几天的博客之后,打算自己写一个练手的程序。
这个程序很简单:客户端发送一个ping
,服务端会相应地回复一个pong
,当监测到服务端失去连接后,即断开。
整个代码分为client与server两部分,结构如下:
引入netty包:
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.15.Final</version>
</dependency>
client端:
PingClient.java
java">package org.attempt.netty4.demo001.client;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
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.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
public class PingClient {
/** 服务器IP地址 */
private String host = "127.0.0.1";
/** 服务器端口 */
private int port = 8000;
private EventLoopGroup group = null;
private Bootstrap b = null;
private Channel channel = null;
public PingClient() throws Exception {
group = new NioEventLoopGroup();
b = new Bootstrap();
b.group(group)
.option(ChannelOption.SO_KEEPALIVE, true)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel channel) throws Exception {
channel.pipeline()
//字符串解码和编码
.addLast(new StringDecoder())
.addLast(new StringEncoder())
//客户端的逻辑
.addLast(new PingClientHandler());
}
});
}
public Channel getChannel() throws Exception {
if(null == channel || !channel.isActive()) {
channel = b.connect(host, port).sync().channel();
}
return channel;
}
public static void main(String[] args) throws Exception {
PingClient client = null;
try {
client = new PingClient();
Channel channel = client.getChannel();
while(true) {
//输出channel的状态,对应于close()
System.out.println(channel.isOpen());
//判断连接状态
if(channel.isActive()) {
channel.writeAndFlush("ping");
} else {
System.out.println("失去连接,关闭客户端");
channel.close();
break;
}
Thread.sleep(5000);
}
} finally {
if(null != client) {
client.stop();
}
}
}
public void stop() {
if(null != group) {
//优雅退出,释放线程池资源
group.shutdownGracefully();
}
}
}
PingClientHandler.java
java">package org.attempt.netty4.demo001.client;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
public class PingClientHandler extends SimpleChannelInboundHandler {
@Override
protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("receive from server: " + msg.toString());
}
}
server端: PongServer.java
java">package org.attempt.netty4.demo001.server;
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.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
public class PongServer {
public static void main(String[] args) throws Exception {
int port = 8000;
if (args != null && args.length > 0) {
try {
port = Integer.valueOf(args[0]);
} catch (NumberFormatException e) {
//采用默认值
}
}
new PongServer().bind(port);
}
public void bind(int port) throws Exception {
//配置服务端的NIO线程组
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel channel) throws Exception {
channel.pipeline()
//字符串解码和编码
.addLast(new StringDecoder())
.addLast(new StringEncoder())
//服务器的逻辑
.addLast(new PongServerHandler());
}
});
//绑定端口,同步等待成功
ChannelFuture f = b.bind(port).sync();
//等待服务器监听端口关闭
f.channel().closeFuture().sync();
} finally {
//优雅退出,释放线程池资源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
PongServerHandler.java
java">package org.attempt.netty4.demo001.server;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
/**
* @author admin
* @date 2018-09-06 22:48
*/
public class PongServerHandler extends SimpleChannelInboundHandler {
@Override
protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("receive from client: " + msg.toString());
//返回客户端消息
if(msg.toString().equals("ping")) {
ctx.writeAndFlush("pong");
} else {
ctx.writeAndFlush("UNKONWN");
}
}
}
运行,先启动server端,再启动client端,结果如下:
- server端:
receive from client: ping
receive from client: ping
receive from client: ping
receive from client: ping
receive from client: ping
Process finished with exit code -1
- client端:
true
receive from server: pong
true
receive from server: pong
true
receive from server: pong
true
receive from server: pong
true
receive from server: pong
false
失去连接,关闭客户端
代码中的一些类及用法,后面再说。