一、Http 服务
1、项目需求
1)服务器监听8001端口,浏览器发送请求 http://localhost:8001 2)服务器可以回复消息给客户端 “Hello 我是服务器”,并对特定请求资源进行过滤
2、案例代码
2.1、Service
public class HttpService {
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 HttpServiceInitializer());
ChannelFuture channelFuture = serverBootstrap.bind(8001).sync();
channelFuture.channel().closeFuture().sync();
}finally{
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
2.2、ServiceInitializer
public class HttpServiceInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("MyHttpServerCodec",new HttpServerCodec());
pipeline.addLast("MyHttpServiceHandler", new HttpServiceHandler());
}
}
2.3、ServiceHandler
public class HttpServiceHandler extends SimpleChannelInboundHandler<HttpObject> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
if(msg instanceof HttpRequest){
System.out.println("msg type= " + msg.getClass());
System.out.println("client address: " + ctx.channel().remoteAddress());
ByteBuf content = Unpooled.copiedBuffer("Hello I am Server side",
CharsetUtil.UTF_8);
FullHttpResponse 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());
ctx.writeAndFlush(response);
}
}
}
2.4、请求过滤
HttpRequest httpRequest = (HttpRequest) msg;
URI uri = new URI(httpRequest.uri());
String path = "/favicon.ico";
if(path.equals(uri.getPath())){
System.out.println("Client has request favicon.ico, not response");
return;
}
在 ServiceHandler 的channelRead0 方法里添加上述代码段,就可以对特定的请求进行过滤,不做响应。
二、WebSocket 长连接
1、案例要求
1)基于WebSocket 实现长连接的全双工交互 2)改变 http 协议多次请求的约束,实现长连接,服务器可以发送消息 3)客户端和服务器端可以相互感知,如服务器关闭了,浏览器会感知;浏览器关闭了,服务器端同样会感知
2、案例代码
2.1、Server
public class Server {
public static void main(String[] args) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap
.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(
new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new HttpServerCodec());
pipeline.addLast(new ChunkedWriteHandler());
pipeline.addLast(new HttpObjectAggregator(8192));
pipeline.addLast(new WebSocketServerProtocolHandler("/hello"));
pipeline.addLast(new MyWebsocketHandler());
}
});
ChannelFuture future = bootstrap.bind(8001).sync();
future.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
2.2、ServerHandler
public class MyWebsocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg)
throws Exception {
System.out.println("received msg: " + msg.text());
ctx.channel().writeAndFlush(new TextWebSocketFrame("server time: " +
LocalDateTime.now() + msg.text()));
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
System.out.println(ctx.channel().remoteAddress() + "上线, id=[" +
ctx.channel().id().asLongText() + "]");
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
System.out.println(ctx.channel().remoteAddress() + "下线, id=[" +
ctx.channel().id().asLongText() + "]");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("Exception= " + cause.getMessage());
ctx.close();
}
}
2.3、Client
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>WebSocketClient</title>
</head>
<body>
<script>
let socket;
if(window.WebSocket){
socket = new WebSocket("ws://localhost:8001/hello");
socket.onmessage = function (event){
let rt = document.getElementById(`responseText`);
rt.value = rt.value + "\n" + event.data + "\n";
}
socket.onopen = function (event) {
let rt = document.getElementById(`responseText`);
rt.value = "connect startup !!\n";
}
socket.onclose = function (event) {
let rt = document.getElementById(`responseText`);
rt.value = rt.value + "connect shutdown !!\n";
}
}else{
alert("Sorry, your browser is not support websocket");
}
function send(message) {
if(socket.readyState === WebSocket.CLOSED){
alert("Websocket has closed!!");
return;
}
if(socket.readyState === WebSocket.OPEN){
socket.send(message);
}else{
alert("websocket connect has not been built");
}
}
</script>
<form onsubmit="return false">
<label>
<textarea name="msg" style="height: 300px; width: 300px"></textarea>
</label>
<input type="button" value="sent" onclick="send(this.form.msg.value)">
<label for="responseText">服务器回复:</label>
<textarea id="responseText" style="height: 300px; width: 300px"></textarea>
<input type="button" value="清空内容"
onclick="document.getElementById('responseText').value=''">
</form>
</body>
</html>
2.4、测试
在这里插入图片描述
|