netty做一个posp的网络_Java网络通信基础系列-Netty实现HTTP服务

一.Netty实现HTTP服务

HTTP程序开发: 在进行WEB开发过程之中,HTTP是主要的通讯协议 ,但是你千万要记住一个问题,HTTP都是基于TCP协议的一种应用,HTTP是在TCP的基础上完善出来的。 TCP是一种可靠的连接协议,所以TCP的执行性能未必会高。据说google正在开发HTTP 3.0技术标准,并且这个技术里面将使用UDP协议作为HTTP基础协议 。

HTTP里面存在有请求模式:

A:HTTP 1.0:GET、POST、HEAD

B:HTTP 1.1:OPTIONS、PUT、DELETE、TRACE、CONNECT,像Restful架构里面就认为这样的请求模式的区分操作非常的明智,但是从另外一个角度来讲,这样的操作实际上会非常麻烦,所以到了Spring实现的Restful架构的时候就不推荐这样的设计了。

HTTP在进行处理的时候操作分为两类数据内容:真实请求数据、头部信息(语言、浏览器内核、Cookie)。

在进行HTTP处理的时候还需要考虑到回应的操作问题:response里面给定的状态码。

Netty可以实现HTTP协议开发,但是需要注意的是,在Netty之中服务器的开发需要考虑两种不同的状态: 处理请求:HttpRequest 处理数据:HttpContent

处理Session与Cookie 服务器端应该进行session的统一管理,应该建立HttpSession的操作标准 需要设置保存在客户端的Sesson的Cookie名称。

HTTP客户端种类: 普通用户:浏览器; 正常开发者:HttpClient、Netty 数据流底层协议开发:Uri程序类完成处理。

二.使用Netty实现了一个基础的HTTP服务器开发,实现请求信息返回

HttpServerMain.java

packagecom.bijian.http.server.main;importcom.bijian.http.server.HttpServer;public classHttpServerMain {public static void main(String[] args) throwsException {newHttpServer().run();

}

}

HttpServer.java

packagecom.bijian.http.server;importcom.bijian.http.server.handler.HttpServerHandler;importcom.bijian.info.HostInfo;importio.netty.bootstrap.ServerBootstrap;importio.netty.channel.ChannelFuture;importio.netty.channel.ChannelInitializer;importio.netty.channel.ChannelOption;importio.netty.channel.EventLoopGroup;importio.netty.channel.nio.NioEventLoopGroup;importio.netty.channel.socket.SocketChannel;importio.netty.channel.socket.nio.NioServerSocketChannel;importio.netty.handler.codec.http.HttpRequestDecoder;importio.netty.handler.codec.http.HttpResponseEncoder;public classHttpServer {public void run() throwsException {//线程池是提升服务器性能的重要技术手段,利用定长的线程池可以保证核心线程的有效数量//在Netty之中线程池的实现分为两类:主线程池(接收客户端连接)、工作线程池(处理客户端连接)

EventLoopGroup bossGroup = new NioEventLoopGroup(10); //创建接收线程池

EventLoopGroup workerGroup = new NioEventLoopGroup(20); //创建工作线程池

System.out.println("服务器启动成功,监听端口为:" +HostInfo.PORT);try{//创建一个服务器端的程序类进行NIO启动,同时可以设置Channel

ServerBootstrap serverBootstrap = new ServerBootstrap(); //服务器端//设置要使用的线程池以及当前的Channel类型

serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class);//接收到信息之后需要进行处理,于是定义子处理器

serverBootstrap.childHandler(new ChannelInitializer() {

@Overrideprotected void initChannel(SocketChannel socketChannel) throwsException {

socketChannel.pipeline().addLast(new HttpResponseEncoder()) ; //响应编码

socketChannel.pipeline().addLast(new HttpRequestDecoder()) ; //请求解码

socketChannel.pipeline().addLast(newHttpServerHandler()) ;

}

});//可以直接利用常亮进行TCP协议的相关配置

serverBootstrap.option(ChannelOption.SO_BACKLOG, 128);

serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE,true);//ChannelFuture描述的时异步回调的处理操作

ChannelFuture future =serverBootstrap.bind(HostInfo.PORT).sync();

future.channel().closeFuture().sync();//等待Socket被关闭

} finally{

workerGroup.shutdownGracefully() ;

bossGroup.shutdownGracefully() ;

}

}

}

HttpServerHandler.java

packagecom.bijian.http.server.handler;importio.netty.buffer.ByteBuf;importio.netty.buffer.Unpooled;importio.netty.channel.ChannelFutureListener;importio.netty.channel.ChannelHandlerContext;importio.netty.channel.ChannelInboundHandlerAdapter;import io.netty.handler.codec.http.*;importio.netty.util.CharsetUtil;public class HttpServerHandler extendsChannelInboundHandlerAdapter {privateHttpRequest request;privateDefaultFullHttpResponse response ;

@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throwsException {if (msg instanceof HttpRequest) { //实现HTTP请求处理操作

this.request = (HttpRequest) msg; //获取Request对象

System.out.println("【Netty-HTTP服务器端】uri = " + this.request.uri() + ",Method = " + this.request.method() + ",Headers = " +request.headers());

String content=

"" +

"

" +

"

Hello Netty" +

" " +

"

" +

"

好好学习,天天向上

" +

" " +

""; //HTTP服务器可以回应的数据就是HTML代码

this.responseWrite(ctx,content);

}

}private voidresponseWrite(ChannelHandlerContext ctx,String content) {

ByteBuf buf=Unpooled.copiedBuffer(content,CharsetUtil.UTF_8) ;this.response = newDefaultFullHttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.OK,buf) ;this.response.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/html;charset=UTF-8") ; //设置MIME类型

this.response.headers().set(HttpHeaderNames.CONTENT_LENGTH,String.valueOf(buf.readableBytes())) ; //设置回应数据长度

ctx.writeAndFlush(this.response).addListener(ChannelFutureListener.CLOSE) ; //数据回应完毕之后进行操作关闭

}

@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throwsException {

cause.printStackTrace();

ctx.close();

}

}

三.实现HTTP访问下的Cookie与Session管理机制

HttpSession.java

packagecom.bijian.http.server.component;/*** 与JavaWEB开发接口标准完全同步*/

public interfaceHttpSession {public static final String SESSIONID = "XiaoLilLaoShiSessionId";publicObject getAttribute(String name) ;public voidsetAttribute(String name, Object value) ;public voidremoveAttribute(String name) ;publicString getId() ;public voidinvalidate() ;

}

DefaultHttpSession.java

packagecom.bijian.http.server.component.impl;importcom.bijian.http.server.component.HttpSession;importjava.util.HashMap;importjava.util.Map;importjava.util.UUID;public class DefaultHttpSession implementsHttpSession {privateString sessionId;private Map attributes = new HashMap();publicDefaultHttpSession() {this.sessionId = UUID.randomUUID().toString() ; //随机生成一个 SessionId

}

@OverridepublicObject getAttribute(String name) {return this.attributes.get(name);

}

@Overridepublic voidsetAttribute(String name, Object value) {this.attributes.put(name,value) ;

}

@Overridepublic voidremoveAttribute(String name) {this.attributes.remove(name) ;

}

@OverridepublicString getId() {return this.sessionId;

}

@Overridepublic voidinvalidate() {this.sessionId = null;

}

}

HttpSessionManager.java

packagecom.bijian.http.server.component;importcom.bijian.http.server.component.impl.DefaultHttpSession;importjava.util.Map;importjava.util.concurrent.ConcurrentHashMap;/*** 实现一个session操作的并发管理程序类*/

public classHttpSessionManager {//在一个Http服务器的进程之中,只允许存在有一个Session保存集合//使用ConcurrentHashMap是因为这个子类会将集合进行分片保存,每一段的数据多线程同步,而不同段进行异步操作

private static final Map SESSION_MAP = new ConcurrentHashMap();/*** 每当有用户连接的时候就需要创建一个SessionId的数据内容

*@returnsessionId*/

public staticString createSession() {

HttpSession session= new DefaultHttpSession() ; //获取了一个SessionId

String sessionId = session.getId() ; //HttpSession实现接口

SESSION_MAP.put(sessionId,session) ;//实现数据集合保存

returnsessionId ;

}/*** 判断当前的SessionId是否存在于集合之中

*@paramsessionId

*@return

*/

public static booleanisExists(String sessionId) {if(SESSION_MAP.containsKey(sessionId)) {

HttpSession session=SESSION_MAP.get(sessionId) ;if (session.getId() == null) { //该Session已经被销毁了

SESSION_MAP.remove(sessionId) ;return false;

}return true;

}else{return false;

}

}public static voidinvalidate(String sessionId) {

SESSION_MAP.remove(sessionId) ;

}public staticHttpSession getSession(String sessionId) {returnSESSION_MAP.get(sessionId) ;

}

}

HttpServerHandler.java

packagecom.bijian.http.server.handler;importcom.bijian.http.server.component.HttpSession;importcom.bijian.http.server.component.HttpSessionManager;importio.netty.buffer.ByteBuf;importio.netty.buffer.Unpooled;importio.netty.channel.ChannelFutureListener;importio.netty.channel.ChannelHandlerContext;importio.netty.channel.ChannelInboundHandlerAdapter;import io.netty.handler.codec.http.*;importio.netty.handler.codec.http.cookie.Cookie;importio.netty.handler.codec.http.cookie.ServerCookieDecoder;importio.netty.handler.codec.http.cookie.ServerCookieEncoder;importio.netty.util.CharsetUtil;importjava.util.Iterator;importjava.util.Set;public class HttpServerHandler extendsChannelInboundHandlerAdapter {privateHttpRequest request;privateDefaultFullHttpResponse response ;privateHttpSession session ;/*** 依据传入的标记内容进行是否向客户端Cookie中保存有SessionId数据的操作

*@paramexists*/

private void setSessionId(booleanexists) {if(exists == false) { //用户发送来的头信息里面不包含有SessionId内容

String encodeCookie =ServerCookieEncoder.STRICT.encode(HttpSession.SESSIONID, HttpSessionManager.createSession()) ;this.response.headers().set(HttpHeaderNames.SET_COOKIE,encodeCookie) ;//客户端保存Cookie数据

}

}/*** 当前所发送的请求里面是否存在有指定的 SessionID数据信息

*@return如果存在返回true,否则返回false*/

public booleanisHasSessionId() {

String cookieStr= this.request.headers().get(HttpHeaderNames.COOKIE) ; //获取客户端头信息发送来的Cookie数据

if (cookieStr == null || "".equals(cookieStr)) {return false;

}

Set cookieSet =ServerCookieDecoder.STRICT.decode(cookieStr);

Iterator iter =cookieSet.iterator() ;while(iter.hasNext()) {

Cookie cookie=iter.next() ;if(HttpSession.SESSIONID.equals(cookie.name())) {if(HttpSessionManager.isExists(cookie.value())) {this.session =HttpSessionManager.getSession(cookie.value()) ;return true;

}

}

}return false;

}

@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throwsException {if (msg instanceof HttpRequest) { //实现HTTP请求处理操作

this.request = (HttpRequest) msg; //获取Request对象

System.out.println("【Netty-HTTP服务器端】uri = " + this.request.uri() + ",Method = " + this.request.method() + ",Headers = " +request.headers());

String content=

"" +

"

" +

"

Hello Netty" +

" " +

"

" +

"

好好学习,天天向上

" +

" " +

""; //HTTP服务器可以回应的数据就是HTML代码

this.responseWrite(ctx,content);

}

}private voidresponseWrite(ChannelHandlerContext ctx,String content) {

ByteBuf buf=Unpooled.copiedBuffer(content,CharsetUtil.UTF_8) ;this.response = newDefaultFullHttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.OK,buf) ;this.response.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/html;charset=UTF-8") ; //设置MIME类型

this.response.headers().set(HttpHeaderNames.CONTENT_LENGTH,String.valueOf(buf.readableBytes())) ; //设置回应数据长度

this.setSessionId(this.isHasSessionId());

ctx.writeAndFlush(this.response).addListener(ChannelFutureListener.CLOSE) ; //数据回应完毕之后进行操作关闭

}

@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throwsException {

cause.printStackTrace();

ctx.close();

}

}

测试发现,这个Name为XiaoLilLaoShiSessionId的Session的Value在第一次请求后生成,后面刷新网页是不变的,即成功实现HTTP访问下的Cookie与Session管理机制。

四.使用Netty访问Http服务器的客户端

HttpClientMain.java

packagecom.bijian.http.client.main;importcom.bijian.http.client.HttpClient;public classHttpClientMain {public static void main(String[] args) throwsException {newHttpClient().run();

}

}

HttpClient.java

packagecom.bijian.http.client;importcom.bijian.http.client.handler.HttpClientHandler;importcom.bijian.info.HostInfo;importio.netty.bootstrap.Bootstrap;importio.netty.channel.ChannelFuture;importio.netty.channel.ChannelInitializer;importio.netty.channel.EventLoopGroup;importio.netty.channel.nio.NioEventLoopGroup;importio.netty.channel.socket.SocketChannel;importio.netty.channel.socket.nio.NioSocketChannel;import io.netty.handler.codec.http.*;public classHttpClient {public void run() throwsException {//1、如果现在客户端不同,那么也可以不使用多线程模式来处理;//在Netty中考虑到代码的统一性,也允许你在客户端设置线程池

EventLoopGroup group = new NioEventLoopGroup(); //创建一个线程池

try{

Bootstrap client= new Bootstrap(); //创建客户端处理程序

client.group(group).channel(NioSocketChannel.class)

.handler(new ChannelInitializer() {

@Overrideprotected void initChannel(SocketChannel socketChannel) throwsException {

socketChannel.pipeline().addLast(new HttpResponseDecoder()); //追加了处理器

socketChannel.pipeline().addLast(new HttpRequestEncoder()); //追加了处理器

socketChannel.pipeline().addLast(new HttpClientHandler()); //追加了处理器

}

});

ChannelFuture channelFuture=client.connect(HostInfo.HOST_NAME, HostInfo.PORT).sync();

String url= "http://" + HostInfo.HOST_NAME + ":" + HostInfo.PORT ; //HTTP访问地址

DefaultFullHttpRequest request= newDefaultFullHttpRequest(HttpVersion.HTTP_1_1,HttpMethod.GET,url) ;

request.headers().set(HttpHeaderNames.HOST,"127.0.0.1") ;

request.headers().set(HttpHeaderNames.CONNECTION,HttpHeaderValues.KEEP_ALIVE) ;

request.headers().set(HttpHeaderNames.CONTENT_LENGTH,String.valueOf(request.content().readableBytes())) ;

request.headers().set(HttpHeaderNames.COOKIE,"nothing") ;

channelFuture.channel().writeAndFlush(request) ;//发送请求

channelFuture.channel().closeFuture().sync(); //关闭连接

} finally{

group.shutdownGracefully();

}

}

}

HttpClientHandler.java

packagecom.bijian.http.client.handler;importio.netty.buffer.ByteBuf;importio.netty.channel.ChannelHandlerContext;importio.netty.channel.ChannelInboundHandlerAdapter;importio.netty.handler.codec.http.HttpContent;importio.netty.handler.codec.http.HttpHeaderNames;importio.netty.handler.codec.http.HttpResponse;importio.netty.handler.codec.http.cookie.ServerCookieDecoder;importio.netty.util.CharsetUtil;public class HttpClientHandler extendsChannelInboundHandlerAdapter {

@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throwsException {if (msg instanceofHttpResponse) {

HttpResponse response=(HttpResponse) msg;

System.out.println("【Netty-Http客户端】ContenType = " +response.headers().get(HttpHeaderNames.CONTENT_TYPE));

System.out.println("【Netty-Http客户端】ContentLength = " +response.headers().get(HttpHeaderNames.CONTENT_LENGTH));

System.out.println("【Netty-Http客户端】SET-COOKIE = " +ServerCookieDecoder.STRICT.decode(response.headers().get(HttpHeaderNames.SET_COOKIE)));

}if (msg instanceofHttpContent) {

HttpContent content=(HttpContent) msg ;

ByteBuf buf= content.content() ; //获取数据信息

System.out.println("【Netty-HTTP客户端】" +buf.toString(CharsetUtil.UTF_8));

}

}

@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throwsException {

cause.printStackTrace();

ctx.close();

}

}

先启动服务端,再启动客户端,运行效果如下:

五.使用Netty实现Http协议下的图片传输与显示处理

HttpServer.java

packagecom.bijian.http.server;importcom.bijian.http.server.handler.HttpServerHandler;importcom.bijian.info.HostInfo;importio.netty.bootstrap.ServerBootstrap;importio.netty.channel.ChannelFuture;importio.netty.channel.ChannelInitializer;importio.netty.channel.ChannelOption;importio.netty.channel.EventLoopGroup;importio.netty.channel.nio.NioEventLoopGroup;importio.netty.channel.socket.SocketChannel;importio.netty.channel.socket.nio.NioServerSocketChannel;importio.netty.handler.codec.http.HttpRequestDecoder;importio.netty.handler.codec.http.HttpResponseEncoder;importio.netty.handler.codec.http.multipart.DiskFileUpload;importio.netty.handler.stream.ChunkedWriteHandler;public classHttpServer {static{

DiskFileUpload.baseDirectory= System.getProperty("user.dir") + "/echo-http/upload/";

}public void run() throwsException {//线程池是提升服务器性能的重要技术手段,利用定长的线程池可以保证核心线程的有效数量//在Netty之中线程池的实现分为两类:主线程池(接收客户端连接)、工作线程池(处理客户端连接)

EventLoopGroup bossGroup = new NioEventLoopGroup(10); //创建接收线程池

EventLoopGroup workerGroup = new NioEventLoopGroup(20); //创建工作线程池

System.out.println("服务器启动成功,监听端口为:" +HostInfo.PORT);try{//创建一个服务器端的程序类进行NIO启动,同时可以设置Channel

ServerBootstrap serverBootstrap = new ServerBootstrap(); //服务器端//设置要使用的线程池以及当前的Channel类型

serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class);//接收到信息之后需要进行处理,于是定义子处理器

serverBootstrap.childHandler(new ChannelInitializer() {

@Overrideprotected void initChannel(SocketChannel socketChannel) throwsException {

socketChannel.pipeline().addLast(new HttpResponseEncoder()) ; //响应编码

socketChannel.pipeline().addLast(new HttpRequestDecoder()) ; //请求解码

socketChannel.pipeline().addLast(new ChunkedWriteHandler()) ; //图片传输处理器

socketChannel.pipeline().addLast(newHttpServerHandler()) ;

}

});//可以直接利用常亮进行TCP协议的相关配置

serverBootstrap.option(ChannelOption.SO_BACKLOG, 128);

serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE,true);//ChannelFuture描述的时异步回调的处理操作

ChannelFuture future =serverBootstrap.bind(HostInfo.PORT).sync();

future.channel().closeFuture().sync();//等待Socket被关闭

} finally{

workerGroup.shutdownGracefully() ;

bossGroup.shutdownGracefully() ;

}

}

}

HttpServerHandler.java

packagecom.bijian.http.server.handler;importcom.bijian.http.server.component.HttpSession;importcom.bijian.http.server.component.HttpSessionManager;importio.netty.buffer.ByteBuf;importio.netty.buffer.Unpooled;importio.netty.channel.ChannelFuture;importio.netty.channel.ChannelFutureListener;importio.netty.channel.ChannelHandlerContext;importio.netty.channel.ChannelInboundHandlerAdapter;import io.netty.handler.codec.http.*;importio.netty.handler.codec.http.cookie.Cookie;importio.netty.handler.codec.http.cookie.ServerCookieDecoder;importio.netty.handler.codec.http.cookie.ServerCookieEncoder;importio.netty.handler.codec.http.multipart.DiskFileUpload;importio.netty.handler.stream.ChunkedFile;importio.netty.util.CharsetUtil;importjavax.activation.MimetypesFileTypeMap;importjava.io.File;importjava.util.Iterator;importjava.util.Set;public class HttpServerHandler extendsChannelInboundHandlerAdapter {privateHttpRequest request;privateDefaultFullHttpResponse response ;privateHttpSession session ;privateChannelHandlerContext ctx ;/*** 依据传入的标记内容进行是否向客户端Cookie中保存有SessionId数据的操作

*@paramexists*/

private void setSessionId(booleanexists) {if(exists == false) { //用户发送来的头信息里面不包含有SessionId内容

String encodeCookie =ServerCookieEncoder.STRICT.encode(HttpSession.SESSIONID, HttpSessionManager.createSession()) ;this.response.headers().set(HttpHeaderNames.SET_COOKIE,encodeCookie) ;//客户端保存Cookie数据

}

}/*** 当前所发送的请求里面是否存在有指定的 SessionID数据信息

*@return如果存在返回true,否则返回false*/

public booleanisHasSessionId() {

String cookieStr= this.request.headers().get(HttpHeaderNames.COOKIE) ; //获取客户端头信息发送来的Cookie数据

if (cookieStr == null || "".equals(cookieStr)) {return false;

}

Set cookieSet =ServerCookieDecoder.STRICT.decode(cookieStr);

Iterator iter =cookieSet.iterator() ;while(iter.hasNext()) {

Cookie cookie=iter.next() ;if(HttpSession.SESSIONID.equals(cookie.name())) {if(HttpSessionManager.isExists(cookie.value())) {this.session =HttpSessionManager.getSession(cookie.value()) ;return true;

}

}

}return false;

}

@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throwsException {this.ctx =ctx ;if (msg instanceof HttpRequest) { //实现HTTP请求处理操作

this.request = (HttpRequest) msg; //获取Request对象

System.out.println("【Netty-HTTP服务器端】uri = " + this.request.uri() + "、Method = " + this.request.method() + "、Headers = " +request.headers());this.handleUrl(this.request.uri());

}

}private voidresponseWrite(String content) {

ByteBuf buf=Unpooled.copiedBuffer(content,CharsetUtil.UTF_8) ;this.response = newDefaultFullHttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.OK,buf) ;this.response.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/html;charset=UTF-8") ; //设置MIME类型

this.response.headers().set(HttpHeaderNames.CONTENT_LENGTH,String.valueOf(buf.readableBytes())) ; //设置回应数据长度

this.setSessionId(this.isHasSessionId());

ctx.writeAndFlush(this.response).addListener(ChannelFutureListener.CLOSE) ; //数据回应完毕之后进行操作关闭

}public voidinfo() {

String content=

"" +

"

" +

"

Hello Netty" +

" " +

"

" +

"

好好学习,天天向上

" +

" " +

" " +

""; //HTTP服务器可以回应的数据就是HTML代码

this.responseWrite(content);

}public voidfavicon() {try{this.sendImage("favicon.ico");

}catch(Exception e) {

e.printStackTrace();

}

}private void sendImage(String fileName) throwsException {

String filePath= DiskFileUpload.baseDirectory +fileName ;

File sendFile= newFile(filePath) ;

HttpResponse imageResponse= newDefaultHttpResponse(HttpVersion.HTTP_1_1,HttpResponseStatus.OK) ;//imageResponse.headers().set(HttpHeaderNames.CONTENT_LENGTH,String.valueOf(sendFile.length())) ;

MimetypesFileTypeMap mimeMap = newMimetypesFileTypeMap() ;

imageResponse.headers().set(HttpHeaderNames.CONTENT_TYPE,mimeMap.getContentType(sendFile)) ;

imageResponse.headers().set(HttpHeaderNames.CONNECTION,HttpHeaderValues.KEEP_ALIVE) ;this.ctx.writeAndFlush(imageResponse) ;this.ctx.writeAndFlush(newChunkedFile(sendFile)) ;//在多媒体信息发送完毕只后需要设置一个空的消息体,否则内容无法显示

ChannelFuture channelFuture = this.ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT) ;

channelFuture.addListener(ChannelFutureListener.CLOSE) ;

}public voidhandleUrl(String uri) {if ("/info".equals(uri)) {this.info();

}else if ("/favicon.ico".equals(uri)) {this.favicon();

}else if ("/show.png".equals(uri)) {this.show() ;

}

}public voidshow() {try{this.sendImage("show.png");

}catch(Exception e) {

e.printStackTrace();

}

}

@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throwsException {

cause.printStackTrace();

ctx.close();

}

}

附:TestSeparator.java

packagecom.bijian;public classTestSeparator {public static voidmain(String[] args) {//System.getProperties().list(System.out);

System.out.println(System.getProperty("line.separator"));

System.out.println(System.getProperty("user.dir") + "/echo-http/upload/");

}

}

运行结果如下:

PS:其它知识

Java基本功:合理的类设计+多线程(JUC)+反射机制+网络通讯+数据结构+JVM

Shiro、SpringDataJPA、MyBatis、OAuth软件设计方法、Linux使用需要熟练(如果你可以独立的实现一套分布式的认证于授权管理,那么就证明你的水平不低了。

架构师经常需要精通几门语言。

docker+k8s+devops。

特别说明:这是开课吧的公开课,完整代码也是讲课老师在GitHub上的代码,我仅只是下载到本地改了一下包名运行调试。完整代码及相关阶段的提交历史我Fork了一份:https://github.com/bijian1013/echo

你可能感兴趣的:(netty做一个posp的网络)