案例演示:创建客户端和服务端,实现客户端与服务端建立连接,并且发送消息给服务端
请尝试阅读代码,并理解注释的含义
1.服务端代码实现
public class Server {
public static void main(String[] args) {
//serverBootstrap,就是服务端启动器,启动服务端,并且绑定组件
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap
//设置NIOEventLoopGroup包含一组NIOEventLoop,NIOEventLoop其实就是一个单线程(维护Selector,处理channel的请求)
//这里我们设置两个NIOEventLoopGroup,一个充当Boss专门处理连接请求,一个充当Woker专门处理IO读写请求
.group(new NioEventLoopGroup(),new NioEventLoopGroup())
//设置通道类型服务端就是NioServerSocketChannel,客户端是NioSocketChannel
.channel(NioServerSocketChannel.class)
//这里设置的就是Woker(child)的处理器,也就是IO读写的具体实现
.childHandler(new ChannelInitializer<NioSocketChannel>() {
//初始化处理器,处理器用于IO处理的具体实现,把多个处理器加入到pipeline中形成一条处理器连,线程会一次执行这些处理器来完成指定的IO操作
@Override
protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
ChannelPipeline pipeline = nioSocketChannel.pipeline();
pipeline.addLast(new StringDecoder());//解析器,收到Bytebuffer数据解析成字符串
pipeline.addLast(new ChannelInboundHandlerAdapter() {//自定义处理器
//当收到数据的时候会触发这个方法
@Override
public void channelRead(ChannelHandlerContext channelHandlerContext, Object msg) throws Exception {
System.out.println(msg);//输出收到的数据
}
});
}
})
.bind(8080);//绑定服务器的监听端口
}
}
2.客户端代码实现
public class Cilent {
public static void main(String[] args) throws Exception {
//bootstrap客户端启动器,启动客户端,绑定各个组件
Bootstrap bootstrap = new Bootstrap();
//设置NioEventLoopGroup作为Woker线程组处理IO读写请求,这里因为客户端不需要处理连接请求,所以不需要NioEventLoopGroup作为Boss线程组
Channel channel = bootstrap.group(new NioEventLoopGroup())
//设置通道类型
.channel(NioSocketChannel.class)
//设置Woker线程的处理器,完成IO读写的具体实现,类似于服务端的childHandler
.handler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
nioSocketChannel.pipeline().addLast(new StringEncoder());//编码器,把字符串编码为ByteBuffer
}
})
//向指定IP和端口的服务器发起连接请求
.connect(new InetSocketAddress("localhost",8080))
//同步等待,阻塞直到连接建立成功
.sync()
//连接建立成功之后返回一个通道,这个通道就是与服务器对应连通的,用于通信
.channel();
channel.writeAndFlush("helloWorld");//向服务端发送helloWorld
}
}