目录
服务端实现(支持HTTP/1.1)
客户端实现(支持HTTP GET/POST)
代码结构解析
服务端核心组件:
客户端核心组件:
协议处理流程对比
测试方法
关键协议实现细节
性能优化建议
以下是基于Netty实现HTTP协议的完整客户端和服务端代码,包含详细的协议处理逻辑:
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil;
public class HttpServer {
public static void main(String[] args) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer() {
@Override
protected void initChannel(SocketChannel ch) {
ChannelPipeline p = ch.pipeline();
// HTTP协议编解码器
p.addLast(new HttpServerCodec());
// 消息聚合器(最大聚合5MB)
p.addLast(new HttpObjectAggregator(5 * 1024 * 1024));
// 业务处理器
p.addLast(new HttpServerHandler());
}
})
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture f = b.bind(8080).sync();
System.out.println("HTTP服务端启动成功,端口:8080");
f.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
private static class HttpServerHandler extends SimpleChannelInboundHandler {
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) {
try {
// 1. 解析请求
String uri = req.uri();
HttpMethod method = req.method();
String content = req.content().toString(CharsetUtil.UTF_8);
// 2. 构建响应
String responseMsg = "处理成功\nMethod: " + method + "\nURI: " + uri + "\nBody: " + content;
FullHttpResponse response = new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1,
HttpResponseStatus.OK,
Unpooled.copiedBuffer(responseMsg, CharsetUtil.UTF_8));
// 3. 设置响应头
response.headers()
.set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8")
.setInt(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes())
.set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
// 4. 发送响应
ctx.writeAndFlush(response);
} finally {
ReferenceCountUtil.release(req);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
}
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
public class HttpClient {
public static void main(String[] args) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer() {
@Override
protected void initChannel(Channel ch) {
ChannelPipeline p = ch.pipeline();
p.addLast(new HttpClientCodec());
p.addLast(new HttpObjectAggregator(1024 * 1024));
p.addLast(new HttpClientHandler());
}
});
// 连接到服务端
ChannelFuture f = b.connect("localhost", 8080).sync();
// 构建HTTP请求
FullHttpRequest request = new DefaultFullHttpRequest(
HttpVersion.HTTP_1_1,
HttpMethod.POST,
"/api/data",
Unpooled.copiedBuffer("请求数据", CharsetUtil.UTF_8));
// 设置请求头
request.headers()
.set(HttpHeaderNames.HOST, "localhost")
.set(HttpHeaderNames.CONTENT_TYPE, "text/plain")
.setInt(HttpHeaderNames.CONTENT_LENGTH, request.content().readableBytes())
.set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
// 发送请求
f.channel().writeAndFlush(request);
// 等待连接关闭
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
private static class HttpClientHandler extends SimpleChannelInboundHandler {
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpResponse response) {
try {
// 解析响应
String content = response.content().toString(CharsetUtil.UTF_8);
System.out.println("收到响应:");
System.out.println("状态码:" + response.status().code());
System.out.println("内容:\n" + content);
} finally {
ReferenceCountUtil.release(response);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
}
HttpRequestDecoder
和HttpResponseEncoder
FullHttpRequest
HttpResponseDecoder
和HttpRequestEncoder
处理阶段 |
服务端处理流程 |
客户端处理流程 |
协议解析 |
解码请求(HttpRequestDecoder) |
解码响应(HttpResponseDecoder) |
消息聚合 |
聚合请求(HttpObjectAggregator) |
聚合响应(HttpObjectAggregator) |
业务处理 |
生成HTTP响应 |
处理HTTP响应 |
协议封装 |
编码响应(HttpResponseEncoder) |
编码请求(HttpRequestEncoder) |
java HttpServer
curl -X POST -d "test data" http://localhost:8080/api/data
java HttpClient
// 服务端设置
response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
// 客户端设置
request.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
// 自动设置Content-Length
HttpUtil.setContentLength(response, response.content().readableBytes());
// 服务端开启分块传输
response.headers().set(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED);
if (HttpUtil.is100ContinueExpected(request)) {
ctx.writeAndFlush(new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1,
HttpResponseStatus.CONTINUE));
}
// 开启Netty对象池
System.setProperty("io.netty.allocator.type", "pooled");
// 文件传输使用FileRegion
FileRegion region = new DefaultFileRegion(file, 0, file.length());
ctx.writeAndFlush(region);
// 使用ConnectionPool
Bootstrap bootstrap = new Bootstrap();
GenericObjectPool pool = new GenericObjectPool<>(
new ChannelPooledObjectFactory(bootstrap));
该实现完整覆盖了HTTP/1.1协议的核心功能,包括:
可根据具体业务需求扩展处理逻辑(如添加路由、参数解析、Session管理等)。