Netty是JBOSS提供的一套异步的、事件驱动的网络应用程序开源框架。可以用来快速开发高性能的服务器程序或者客户端程序。本文简单介绍服务端编写,主要程序基本上都是官网上的例子,查阅网上的资料和文档写了一些的注释,测试的客户端就简单使用socket,没有使用netty框架了。
声明一下,程序依赖的netty是4.0版本。
首先要对网络编程有一定的了解,先看看服务端的代码,就不多做解释了,里面有注释。
server 端:
package 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;
public class SocketServer {
private int port;
public SocketServer(int port) {
this.port = port;
}
public void run() throws Exception {
//NioEventLoopGroup是一个多线程的I/O操作事件循环池(参数是线程数量)
//bossGroup主要用于接受所有客户端对服务端的连接
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
//当有新的连接进来时将会被注册到workerGroup(不提供参数,会使用默认的线程数)
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//ServerBootstrap是设置服务器的辅助类
ServerBootstrap bs = new ServerBootstrap();
//group方法是将上面创建的两个EventLoopGroup实例指定到ServerBootstrap实例中去
bs.group(bossGroup, workerGroup)
//channel方法用来创建通道实例(NioServerSocketChannel类来实例化一个进来的连接)
.channel(NioServerSocketChannel.class)
//为新连接到服务器的handler分配一个新的channel。ChannelInitializer用来配置新生成的channel。(如需其他的处理,继续ch.pipeline().addLast(新匿名handler对象)即可)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
//处理逻辑放到SocketHandler类中去
ch.pipeline().addLast(new SocketHandler());
}
})
//option()方法用于设置监听套接字
.option(ChannelOption.SO_BACKLOG, 128)
//childOption()方法用于设置和客户端连接的套接字
.childOption(ChannelOption.SO_KEEPALIVE, true);
// Bind and start to accept incoming connections
ChannelFuture cf = bs.bind(this.port).sync();
// Wait until the session socket is closed.
// shut down your session.
cf.channel().closeFuture().sync();
} finally {
//关闭相关资源
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
new SocketServer(8080).run();
}
}
server逻辑处理:
package server;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
public class SocketHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf in = (ByteBuf)msg;
byte[] b = new byte[50];
int i = 0;
try {
while (in.isReadable()) {
b[i++] = in.readByte();
System.out.flush();
}
} finally {
in.release();
}
String s = new String(b);
System.out.println(s);
//若要将数据发回客户端只需要这样修改
//根据msg做相应的逻辑处理
//ctx.write(msg);
//ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
//close the connection when an exception is raise
cause.printStackTrace();
ctx.close();
}
}
客户端就非常简单了,只是创建了一个tcp的socket,带了一些字符串信息,测试服务端是否完整收发送的内容。
client代码:
package server;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
public class TestClient {
public static void main(String[] args) {
try {
Socket socket = new Socket();
SocketAddress sa = new InetSocketAddress("127.0.0.1", 8080);
socket.connect(sa, 10000);
String msg = "hello, this is client";
byte[] byteMsg = msg.getBytes();
OutputStream os = socket.getOutputStream();
os.write(byteMsg);
os.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
控制台打印信息:
hello, this is client