由于客户端是浏览器,所以只需要编写服务端
服务端:绑定10086端口
package com.jym.http;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
/**
* @program: NettyPro
* @description: 服务端,简单实现http
* @author: jym
* @create: 2020/02/08
*/
public class TestSever {
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 TestSeverInitializer());
ChannelFuture channelFuture = serverBootstrap.bind(10086).sync();
channelFuture.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture channelFuture) {
if(channelFuture.isSuccess()){
System.out.println("监听端口 10086 成功");
} else {
System.out.println("监听端口失败");
}
}
});
channelFuture.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
自定义Initializer需要继承ChannelInitializer重写方法:
package com.jym.http;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;
/**
* @program: NettyPro
* @description:
* @author: jym
* @create: 2020/02/08
*/
public class TestSeverInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
// 向管道加入处理器
//得到管道
ChannelPipeline pipeline = socketChannel.pipeline();
// 加入一个netty提供的httpServer codec
// HttpServerCodec说明
// 1.netty提供的一个http的编--解码器
pipeline.addLast("JymHttpSeverCodec",new HttpServerCodec());
// 增加自定义的处理器
pipeline.addLast("JymHttpSeverHandler",new TestHttpSeverHandler());
}
}
自定义handler,因为浏览器会发送两个请求,一个正常的请求,一个网页图标,要分开处理
package com.jym.http;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;
/**
* @program: NettyPro
* @description: 处理器,SimpleChannelInboundHandler说明:
* 1.是ChannelInboundHandlerAdapter的子类
* 2.HttpObject 客户端和服务器端相互通讯的数据被封装成 HttpObject
* @author: jym
* @create: 2020/02/08
*/
public class TestHttpSeverHandler extends SimpleChannelInboundHandler<HttpObject> {
private static byte[] bytes;
static {
File file = new File("D:\\壁纸\\LOL\\1.jpg");
FileInputStream fi = null;
try {
long fileSize = file.length();
if (fileSize > Integer.MAX_VALUE) {
throw new IOException(file.getName()+"file too big... ");
}
fi = new FileInputStream(file);
bytes = new byte[(int) fileSize];
int offset = 0;
int numRead = 0;
while (offset < bytes.length
&& (numRead = fi.read(bytes, offset, bytes.length - offset)) >= 0) {
offset += numRead;
}
// 确保所有数据均被读取
if (offset != bytes.length) {
throw new IOException("Could not completely read file "
+ file.getName());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fi!=null){
try {
fi.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 读取客户端数据
*/
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, HttpObject httpObject) throws Exception {
// 判断 httpObject 是不是一个HttpRequest请求
if(httpObject instanceof HttpRequest){
System.out.println("msg 类型:"+ httpObject.getClass());
System.out.println("客户端地址:"+channelHandlerContext.channel().remoteAddress());
HttpRequest request = (HttpRequest)httpObject;
URI uri = new URI(request.uri());
ByteBuf content = null;
// 处理图标
if("/favicon.ico".equals(uri.getPath())){
content = Unpooled.copiedBuffer(bytes);
} else {
// 回复信息给浏览器
content = Unpooled.copiedBuffer("hello,我是服务器", CharsetUtil.UTF_8);
}
// 构造一个 httpResponse
DefaultFullHttpResponse response =
new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,content);
// 设置响应头
response.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain");
response.headers().set(HttpHeaderNames.CONTENT_LENGTH,content.readableBytes());
channelHandlerContext.writeAndFlush(response);
}
}
}
SimpleChannelInboundHandler说明:
1.是ChannelInboundHandlerAdapter的子类
2.HttpObject 客户端和服务器端相互通讯的数据被封装成 HttpObject
测试结果:
启动服务端后,访问10086端口:
图标与内容都可正常显示