AndServer流程和使用方法
AndServer提供了在 Android 设备上搭建一个 Web 服务器的源码,它可以接受客户端文件上传、下载文件,相关流程和使用方法如下:
------andserver 关键类
StorageWebsite -> BasicWebsite -> Website -> HandlerAdapter
HandlerAdapter接口提供 是否拦截当前请求方法,获取处理当前请求的RequestHandler。
Website.getHandler(HttpRequest request) 方法返回new RequestHandler创建的RequestHandler对象
DispatcherHandler -> HttpRequestHandler, Register
DispatcherHandler.mAdapterList 存储StorageWebsite对象
-----apache关键类
ServerBootstrap.java
用于启动和配置服务器端应用程序 ,.create方法会调用ServerSocketFactory.getDefault() 创建一个默认服务器套接字, connectionFactoryCopy = DefaultBHttpServerConnectionFactory.INSTANCE
然后调用new HttpServer(...) 返回HttpServer对象
HttpServer.java
用于创建HTTP服务器。它允许开发者创建自己的服务器并处理HTTP请求。
ServerSocketFactory.java
用于创建服务器套接字的抽象类,核心功能是创建服务器套接字ServerSocket
ServerSocket.java
ServerSocket类的作用是创建一个服务器端套接字,它允许服务器程序监听特定的网络端口,等待客户端的连接请求。
一旦有客户端连接到服务器,ServerSocket就会接受这个连接,并返回一个Socket对象,通过这个对象,服务器和客户端之间可以进行数据通信。
一、客户端请求流程:
btn_browse 主界面点击浏览服务器主界面
intent 启动http://" + ip + ":8080/" 网址
二、服务启动
1.服务初始化
启动了CoreService 继承 Service
mService = new Intent(activity, CoreService.class)
CoreService.onCreate()
mServer = AndServer.webServer(this)
.port(8080) //设置端口
.timeout(10, TimeUnit.SECONDS) //超时时间
..
->AndServer.webServer
WebServer.newBuilder(context, "default") mServer 即创建的 WebServer对象
WebServer 继承 BasicServer
2.点击启动服务
mServerManager.startServer()
ServerManager.startServer() 调用mActivity.startService(mService) 启动服务 即:mService = new Intent(activity, CoreService.class)
service 启动会回调
CoreService.onStartCommand
CoreService.startServer() //调用 mServer.startup() mServer 即上面的WebServer对象
BasicServer.startup() 线程中调用mHttpServer = ServerBootstrap.bootstrap() 初始化 ServerBootstrap
.registerHandler("*", requestHandler()) //这个requestHandler() 方法调用的是WebServer.requestHandler()
****注意 即向 web服务器注册 监听 new DispatcherHandler ,DispatcherHandler实现了apache的HttpRequestHandler接口,所以这个类是处理http请求和响应的核心。
mHttpServer.start(); 调用apache启动服务
其中WebServer.requestHandler 调用register.register(handler, mGroup) 这个handler是DispatcherHandler,传递给了下面的register
ComponentRegister.register(Register register, String group) 中遍历 REGISTER_LIST数组,包括ConfigRegister等,调用其中的onRegister方法
ConfigRegister.onRegister 方法中
2.1.调用config.onConfig(context, delegate); config对应AppConfig,delegate对应Delegate
AppConfig.onConfig(context, delegate) 方法调用delegate.addWebsite(new StorageWebsite(carWebPath, AppConstants.INDEX_FILE_NAME));
向Delegate.mWebsites中添加StorageWebsite对象,
2.2.遍历Delegate.mWebsites列表中website 对象调用 register.addAdapter(website),这里的register即对应上面的 DispatcherHandler
DispatcherHandler.addAdapter(adapter) 调用 mAdapterList.add(adapter) 这里的adapter即website参数,即上面的 StorageWebsite,mAdapterList存储StorageWebsite列表
mHttpServer.start(); 调用apache启动http服务会调用如下apache接口。
-------如下是apache接口实现
HttpServer.start() 这里执行如下几步
1.先调用 serverSocketFactory.createServerSocket() 创建ServerSocket
2.绑定ip和端口 调用serverSocket.bind(new InetSocketAddress(this.ifAddress, this.port),因为是服务器这里ifAddress为空,port为8080.
3.设置接收缓冲区大小erverSocket.setReceiveBufferSize
4.将参数封装到RequestListener的Runnable中,然后再线程中执行RequestListener.run()
requestListener = new RequestListener(
this.socketConfig,
this.serverSocket,
this.httpService,
this.connectionFactory,
this.exceptionLogger,
this.workerExecutorService)
4.1 RequestListener.run()执行
4.1.1监听客户端socket请求,调用socket = this.serversocket.accept(),
4.1.2然后基于客户端请求socket创建HttpServerConnection conn, 调用conn = this.connectionFactory.createConnection(socket)
DefaultBHttpServerConnectionFactory.createConnection(final Socket socket) 该方法执行创建DefaultBHttpServerConnection,调用 conn = new DefaultBHttpServerConnection 参数都是空
然后将DefaultBHttpServerConnection绑定到socket,调用 conn.bind(socket)
4.1.3将HttpServerConnection 和httpService封装到Worker Runnable中, 调用worker = new Worker(this.httpService, conn, this.exceptionLogger).
线程中执行Worker.run()
4.2 Worker.run()执行
while (!Thread.interrupted() && this.conn.isOpen()) 循环中处理 httpservice.handleRequest(this.conn, context);
---------核心---------客户端连接时候循环调用handleRequest
HttpService.handleRequest 执行
4.2.1 基于请求的method 获取当前HttpRequest,调用 request = conn.receiveRequestHeader() 最终是从
DefaultBHttpServerConnection.receiveRequestHeader 调用2步
#1.调用ensureOpen()绑定 socket输入,输出流
BHttpConnectionBase.ensureOpen() 将inBuffer绑定socket输入流, 调用inBuffer.bind(getSocketInputStream(socket));
将outbuffer绑定socket输出流, 调用outbuffer.bind(getSocketOutputStream(socket))
#2.调用request = this.requestParser.parse(getSocket()) 基于method参数返回 HttpRequest对象。
其中 requestParser 为DefaultHttpRequestParserFactory.INSTANCE.create(getSessionInputBuffer(), constraints) 返回的new DefaultHttpRequestParser(buffer, lineParser, requestFactory, constraints)对象,
这里的requestFactory为DefaultHttpRequestFactory, lineParser 为BasicLineParser,
getSessionInputBuffer() 为inBuffer,
AbstractMessageParser.parse(Socket socket) 判断state默认是 HEAD_LINE调用 parseHead(socket, this.sessionBuffer) 这里sessionBuffer为inBuffer,将返回的HttpRequest赋值给AbstractMessageParser.message
DefaultHttpRequestParser.parseHead(final Socket socket,SessionInputBuffer sessionBuffer) 通过参数返回method参数返回 HttpRequest对象,
方法调用readLen = sessionBuffer.readLine(this.lineBuf)读取数据到lineBuf; 调用 requestFactory.newHttpRequest(socket, requestline)
其中 requestline = this.lineParser.parseRequestLine(this.lineBuf, cursor) 这里 cursor = new ParserCursor(0, this.lineBuf.length()),lineBuf = new CharArrayBuffer(128)
requestline为解析一行对象RequestLine
BasicLineParser.parseRequestLine 该方法从 lineBuf 字符串中读取出method,uri,ProtocolVersion信息将信息封装到new BasicRequestLine(method, uri, ver)返回。
DefaultHttpRequestFactory.newHttpRequest(Socket socket, RequestLine requestline) 调用从requestline 读取method
如果是 "GET","HEAD","OPTIONS","TRACE","CONNECT" 返回 BasicHttpRequest(socket, method, uri) 对象
如果是"POST", "PUT","DELETE","PATCH" 返回 BasicHttpEntityEnclosingRequest(socket, method, uri)对象
4.2.2 调用doService(request, response, context);
HttpService.doService(...)
#1.调用 handler = this.handlerMapper.lookup(request)从handlerMapper(即UriHttpRequestHandlerMapper)中获取HttpRequestHandler(即DispatcherHandler)
UriHttpRequestHandlerMapper.lookup(final HttpRequest request) 返回 matcher.lookup(getRequestPath(request)) 返回注册的DispatcherHandler
#2.调用handler.handle(request, response, context) 即调用DispatcherHandler.handle处理客户端的请求。
Worker.httpservice初始化过程:
ServerBootstrap.registerHandler("*", requestHandler())
registerHandler() 将pattern和HttpRequestHandler放到handlerMap,ServerBootstrap.create()时将handlerMap 封装到UriHttpRequestHandlerMapper.matcher
然后new HttpService时将UriHttpRequestHandlerMapper封装到HttpService.handlerMapper,
将HttpService封装到 HttpServer.httpService 及 RequestListener.httpService 和Worker.httpservice
requestHandler()即 WebServer.requestHandler() 创建的DispatcherHandler对象
三、服务端接收流程:
DispatcherHandler implements HttpRequestHandler, //HttpRequestHandler 是 apache中的接口
DispatcherHandler.handle
PageControllerIndexHandler.onHandle
PageController.index() 返回 forward:/index.html
四、服务端返回数据给client
DispatcherHandler.handle(org.apache.httpcore.HttpRequest req, org.apache.httpcore.HttpResponse res,
org.apache.httpcore.protocol.HttpContext con)
HttpRequest request = new StandardRequest(req, new StandardContext(con), this, mSessionManager);
HttpResponse response = new StandardResponse(res);
handle(request, response) 将apache返回的HttpResponse和HttpRequest 封装到 HttpResponse response = new StandardResponse(res);
DispatcherHandler.handle 方法中
1.调用DispatcherHandler.getHandlerAdapter 遍历mAdapterList 即遍历上面描述的StorageWebsite列表,调用 ha.intercept(request) ,ha对应 StorageWebsite
StorageWebsite.intercept(@NonNull HttpRequest request) 调用findPathFile(httpPath),遍历当前配置路径下是否有匹配的文件,如果有返回该StorageWebsite
2.调用 RequestHandler handler = ha.getHandler(request) ha对应StorageWebsite,即调用StorageWebsite父类Website中的getHandler方法,该方法返回RequestHandler对象,
3.调用View view = handler.handle(request, response) 即Website.getHandler.RequestHandler.handle中返回的 new BodyView(getBody(request, response) ,BodyView构造函数将getBody的对象赋值给mBody
这里的getBody调用StorageWebsite.getBody 方法 根据request 获取文件路径,生成file对象targetFile, 返回new FileBody(targetFile) ,即BodyView.mBody就是request的FileBody
这里的view就是BodyView
4.调用mViewResolver.resolve(view, request, response)
ViewResolver.resolve(view, request, response)
4.1Object output = view.output(); //view就是BodyView ,BodyView.output 返回mBody,即request的FileBody对象。
4.2ViewResolver.resolveRest(output, request, response)
4.2.1判断如果是request是post请求,则调用 response.setBody(new StringBody(responseJson)) 返回字符串给客户端;
4.2.2 否则 调用 response.setBody((ResponseBody) output) output是request的FileBody对象,response是 StandardResponse,
StandardResponse.setBody(HttpEntity entity) 调用mResponse.setEntity(new BodyToEntity(body)) 即调用 apache HttpResponse.setEntity
apache HttpResponse.setEntity 将FileBody封装到BodyToEntity对象中(body是request的FileBody对象,从StorageWebsite.getBody 获取FileBody)
BodyToEntity对应的writeTo(OutputStream out) ,getContentType(),getContentLength 方法调用的事信息FileBody中对应的接口方法。
即apache HttpEntity 接口调用getContentLength 等方法调用的是FileBody中对应的接口方法。
比如:客户端反馈的 content-length可能不对可以在,StandardResponse.BodyToEntity.getContentLength 即:回调给应用的content-length,
如果是下载文件的最终是取的FileBody.contentLength 返回的要下载文件的 content-length
WebServer 继承
api中 用来调用 apache 中的 HttpServer
BasicServer
.registerHandler("*", requestHandler()) //注册handler 测试添加
.registerHandler("login", new RequestLoginHandler())
.build();复制代码现在你就得到了一个唯一的访问地址:http://ip:port/login, 例如:
http://192.168.1.12:8080/login?username=123&password=123
----------------------------------------
五、服务配置
AppConfig.onConfig ****************************************可以配置对应目录访问对应的图片资源
可以修改策略如果是get请求不拦截直接认为是下载,如果是post作拦截
配置AssetsWebsite 路径等参数
setMultipart 设置客户端上传配置信息
六、源码编译相关
AndServer 源码路径:https://github.com/yanzhenjie/AndServer
编译源码需要将引用的jdk版本修改成1.8,gradle 版本设置成6.7.1
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术