Last time, I tried to create a TCP / IP + NIO / BIO transfer path using libraries such as webSocket and SocketChannel, but I found that the code became quite complicated. This time I will try to realize a server again using Netty.
Simply put, Netty is a framework for developing applications that perform asynchronous communication. Compared to NIO processing realized by SocketChannel, it is no longer necessary to directly operate low-layer APIs (select (), read (), etc.), and it is hidden on the Netty side.
First of all, I will repost the previous Implementing NIO with ServerSocket Channel.
➀ Create a ServerSocketChannel and listen for client-side access
public class ChannelServer {
public static void main(String[] args) throws IOException {
// I/Prepare a thread pool to process O requests
ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 10, 1000, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(100));
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(1234));
while (true) {
SocketChannel socketChannel = serverSocketChannel.accept();
if (socketChannel != null) {
//Commit the request to the thread pool
executor.submit(new ChannelServerThread(socketChannel));
}
}
}
}
② Thread that processes the request
public class ChannelServerThread implements Runnable {
private SocketChannel socketChannel;
private String remoteName;
public ChannelServerThread(SocketChannel socketChannel) throws IOException {
this.socketChannel = socketChannel;
this.remoteName = socketChannel.getRemoteAddress().toString();
System.out.println("client:" + remoteName + " access successfully!");
}
// I/Handle O request
@Override
public void run() {
ByteBuffer buffer = ByteBuffer.allocate(1024);
ByteBuffer sizeBuffer = ByteBuffer.allocate(4);
StringBuilder sb = new StringBuilder();
byte b[];
//Read data and length from socketChannel and output to standard output
while(true) {
try {
sizeBuffer.clear();
int read = socketChannel.read(sizeBuffer);
if (read != -1) {
sb.setLength(0);
sizeBuffer.flip();
int size = sizeBuffer.getInt();
int readCount = 0;
b = new byte[1024];
while (readCount < size) {
buffer.clear();
read = socketChannel.read(buffer);
if (read != -1) {
readCount += read;
buffer.flip();
int index = 0 ;
while(buffer.hasRemaining()) {
b[index++] = buffer.get();
if (index >= b.length) {
index = 0;
sb.append(new String(b,"UTF-8"));
}
}
if (index > 0) {
sb.append(new String(b,"UTF-8"));
}
}
}
System.out.println(remoteName + ":" + sb.toString());
}
} catch (Exception e) {
System.out.println(remoteName + "access colsed");
try {
socketChannel.close();
} catch (IOException ex) {
}
break;
}
}
}
}
➀ Process that waits for access on the client side
public class EchoServer {
private final int port;
public EchoServer(int port) {
this.port = port;
}
public void start() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
ServerBootstrap sb = new ServerBootstrap();
//Thread pool binding
sb.group(group)
.channel(NioServerSocketChannel.class)
//Port number binding
.localAddress(this.port)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
System.out.println("connected...; Client:" + ch.remoteAddress());
ch.pipeline().addLast(new EchoServerHandler());
}
});
//Asynchronous binding of server
ChannelFuture cf = sb.bind().sync();
System.out.println(EchoServer.class + " started and listen on " + cf.channel().localAddress());
//Close server channel
cf.channel().closeFuture().sync();
} finally {
//Unbind thread pool
group.shutdownGracefully().sync();
}
}
public static void main(String[] args) throws Exception {
//entrance
new EchoServer(66666).start();
}
}
② The one who processes the request
public class EchoServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("server channelRead...; received:" + msg);
ctx.write(msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
System.out.println("server channelReadComplete..");
//WriteAndFlush in empty buffer,Close the connection
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("server occur exception:" + cause.getMessage());
cause.printStackTrace();
ctx.close();
}
}
** The amount of code has been greatly reduced. ** ** This is to hide APIs such as read () and Buffer operations from the Netty side and provide a convenient high-layer API. For example, channelRead () method of EchoServerHandler class: When data from the client side is accepted, it is converted to String internally, so this method is called.
This time I tried to implement the server using Netty. I will introduce the cooperation with the client side next time.
Recommended Posts