Detailed Guide to Netty Socket Programming: Building Server and Client for Data Transfer
This tutorial walks through creating a Netty-based socket server and client in Java, covering project setup, event loop groups, channel initializers, codec pipelines, custom handlers, and the activation flow that enables bidirectional message exchange.
Socket Server Setup
Create a new package under src and add a SocketServer class with a main method.
package com.badao.nettySocket;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class SocketServer {
public static void main(String[] args) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new SocketServerInitializer());
ChannelFuture channelFuture = serverBootstrap.bind(70).sync();
channelFuture.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}The server uses ServerBootstrap with two EventLoopGroup s: one for accepting connections (boss) and one for handling traffic (worker). It binds to port 70 and registers SocketServerInitializer as the pipeline configurator.
Server Initializer
package com.badao.nettySocket;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;
public class SocketServerInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
pipeline.addLast(new LengthFieldPrepender(4));
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new SocketServerHandler());
}
}The initializer extends ChannelInitializer<SocketChannel>, adds a length‑field decoder/prepender, string codec, and finally a custom SocketServerHandler.
Server Handler
package com.badao.nettySocket;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
public class SocketServerHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("Server received from " + ctx.channel().remoteAddress() + ": " + msg);
ctx.channel().writeAndFlush("Server response: (公众号:霸道的程序猿)");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}The handler inherits SimpleChannelInboundHandler<String>, prints incoming messages, and replies with a fixed string. It also logs exceptions and closes the channel.
Socket Client Setup
package com.badao.nettySocket;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
public class SocketClient {
public static void main(String[] args) throws Exception {
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup)
.channel(NioSocketChannel.class)
.handler(new SocketClientInitializer());
ChannelFuture channelFuture = bootstrap.connect("localhost", 70);
channelFuture.channel().closeFuture().sync();
} finally {
eventLoopGroup.shutdownGracefully();
}
}
}The client mirrors the server: it creates a single EventLoopGroup, configures a Bootstrap with NioSocketChannel, attaches SocketClientInitializer, and connects to localhost:70.
Client Initializer
package com.badao.nettySocket;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;
public class SocketClientInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
pipeline.addLast(new LengthFieldPrepender(4));
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
pipeline.addLast(new SocketClientHandler());
}
}The client pipeline is identical to the server’s, ending with a custom SocketClientHandler.
Client Handler
package com.badao.nettySocket;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
public class SocketClientHandler extends SimpleChannelInboundHandler<String> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("Client received from " + ctx.channel().remoteAddress() + ": " + msg);
ctx.channel().writeAndFlush("Client sent data: (公众号:霸道的程序猿)");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.writeAndFlush("Client initiates message");
}
}The handler overrides channelActive to send an initial string once the connection is established, then processes inbound messages similarly to the server side.
Running the Example
Execute SocketServer.main first, then SocketClient.main. The client’s channelActive sends a message, triggering the server’s channelRead0, which prints the payload and replies. The client receives the reply, prints it, and sends its own response, creating a continuous exchange.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
The Dominant Programmer
Resources and tutorials for programmers' advanced learning journey. Advanced tracks in Java, Python, and C#. Blog: https://blog.csdn.net/badao_liumang_qizhi
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
