IOS理论知识ios服务器本地服务器

轻量级iOS/OSX服务器GCDWebServer

2015-11-15  本文已影响4883人  寻雨的人

简述


GCDWebServer是一个基于GCD的轻量级服务器框架,用于内嵌到OSX或者iOS系统的应用中提供HTTP1.1的服务。


实现目标


1.设计优雅,易于使用。仅仅包含4个核心类:server, connection, request and response

2.设计良好的API。头文件注释齐全,非常易于继承和定制个性化需求。

3.事件驱动模型。基于GCD框架,实现最佳性能和并发。

4.不依赖任何第三方源码。

5.符合新的BSD许可协议。


额外特性


1.针对http请求,支持完全异步处理

2.针对较大HTTP请求和响应流,采用内存最优化策略

3.支持解析使用"application/x-www-form-urlencoded" 或者 "multipart/form-data"编码格式提交的html表单

4.支持对json格式的请求或响应进行解析和序列化

5.HTTP请求或响应采用分块传输编码

6.HTTP请求和响应采用gzip方式压缩

7.对本地文件的请求支持多种HTTP类型

8.采用通用、简单的密码保护访问认证机制

9.支持在app前台、后台或挂起时自动处理事务

10.完全支持ipv4和ipv6


拓展功能


1.文件上传功能。提供通过浏览器实现文件上传和下载的接口。GCDWebUploader(->GCDWebServer)

2.DAV文件系统服务。DAV不仅被看作HTTP的扩展,甚至被看作一种网络文件系统。(GCDWebDAVServer->GCDWebServer)


不支持


1.长连接

2.https请求


系统要求


1.OS X 10.7 or later (x86_64)

2.iOS 5.0 or later (armv7, armv7s or arm64)

3.仅支持ARC


如何开始


下载最新源码,将整个GCDWebServer目录拷贝到自己的xcode项目目录下,importGCDWebServer.h头文件即可。如果需要使用GCDWebDAVServer或GCDWebUploader,同样拷贝对应的目录到自己的项目工程下。

或者你也可以通过cocoaPods方式引入:

在xcode项目的podfile文件中添加如下语句:

pod "GCDWebServer", "~> 3.0”

如果需要使用上传功能,用下面的替换:

pod "GCDWebServer/WebUploader", "~> 3.0”

如果需要使用DAV功能,用下面的替换:

pod "GCDWebServer/WebDAV", "~> 3.0”


Hello World


由于GCDWebServer采用GCD代码块实现请求处理handler,代码清晰、整洁,因此不需要子类化或者代理方式。

基于iOS应用的实现步骤:

1.Create server

2.添加请求处理句柄(Handle)

3.启动服务器,监听8080端口


异步HTTP响应生成


GCDWebServer 3.0开始,框架拥有异步处理HTTP请求的能力,形如,为服务添加不同的handles来异步生成GCDWebServerResponse响应。要想实现这个功能,添加handle实现时需要使用GCDWebServerAsyncProcessBlock替换GCDWebServerProcessBlock。

生成静态网页

GCDWebServer包含一个内建的handler,可以提供递归地目录服务(也可以让你控制如何设置缓存控制的头部信息)。

#import "GCDWebServer.h"

int main(int argc, const char* argv[]) {

@autoreleasepool {

GCDWebServer* webServer = [[GCDWebServer alloc] init];

[webServer addGETHandlerForBasePath:@"/" directoryPath:NSHomeDirectory() indexFilename:nil cacheAge:3600 allowRangeRequests:YES];

[webServer runWithPort:8080];

}

return 0;

}

GCDWebServer实战


以创建gcdwebserver类的一个实例开始。请注意,你可以有多个Web服务器运行在同一个应用程序中,只要他们监听不同的端口即可。

然后,向服务器添加一个或多个Handler:每个Handler可以处理一个外部传入的Web请求,同时提供/生成响应。Handles处理队列是一个后进先出队列,所以最新添加的handler会覆盖最先添加的handler。

最后,在一个给定的端口上开启服务。

理解GCDWebServer的架构


GCDWebServer架构由4个核心类组成:

1.GCDWebServer辅助管理监听HTTP连接的套接字以及服务器使用的处理器列表。

2.GCDWebServerConnection继承自GCDWebServer,负责处理每个HTTP连接。每个实例都保持连接直到连接关闭。你不能直接使用这个类,但它是暴露的,所以你可以子类化它用于重写一些钩子。

3.GCDWebServerRequest由GCDWebServerConnection的实例在拿到http信息头后创建。它负责 把请求和处理HTTP信息体封装起来。GCDWebServer自带的几个GCDWebServerRequest子类负责处理普通请求,比如保存请求信息在内存或在磁盘上的文件上。

4.GCDWebServerResponse由请求程序的handle创建,负责将响应的HTTP头和body封装起来。GCDWebServer自带的几个GCDWebServerResponse 子类负责处理响应,比如保存请求信息在内存或在磁盘上的文件上。

实现Handlers


GCDWebServer依靠handlers去处理Web请求并生成响应。handlers由GCD块实现,使得你可以很容易实现它们。然而,他们会在GCD中执行任意线程,所以要特别注意线程安全和重入问题。

1.GCDWebServerMatchBlock被添加到GCDWebServer的实例中,当任意请求开始时将会被调用(例如收到http请求的头部信息)。它负责为web请求传递基本信息,并决定是否继续处理。如果是,它必须返回一个新的带有请求信息的GCDWebServerRequest实例(见上文)。否则,它只返回nil。

2.GCDWebServerProcessBlock或GCDWebServerAsyncProcessBlock将在web请求完全接收完毕后调用,并负责传递由上一步生成的GCDWebServerRequest实例。它必须返回同步(如果使用GCDWebServerProcessBlock)或异步(如果使用GCDWebServerAsyncProcessBlock)的GCDWebServerResponse实例(见上文)或带500HTTP状态码返回给客户端的nil。当然,更推荐返回GCDWebServerErrorResponse实例,这样一来可以更多有用的信息返回给客户端。

注意,大多数添加handlers的GCDWebServer方法只期望GCDWebServerProcessBlock或GCDWebServerAsyncProcessBlock,因为他们已经提供了一个内置的GCDWebServerMatchBlock,例如带有正则表达式匹配的URL路径。


GCDWebServer的后台模式处理


当在iOS应用中处理网络操作时,你必须小心处理当iOS应用程序进入后台的情况。通常情况,当应用程序在后台时,你必须停止所有网络服务器,当应用程序返回到前台时再重新启动。考虑到服务器可能有正在进行的连接时,他们需要停止,这种场景可能会变得相当复杂。

幸运的是,GCDWebServer已经自动为你处理了上述所有事情。

1.在第一个HTTP连接打开时,GCDWebServer将开启一个后台任务,当最后一个HTTP连接断开时这个后台任务将结束。这可以防止当iOS App进入后台时挂起,挂起后app会立即杀死所有与客户端直连的HTTP连接。

当应用程序进入后台时,只要新的HTTP连接被启动,这个后台任务将继续存在和并且iOS不会挂起应用程序(除非突然和意外的内存压力下)。

如果当最后一个HTTP连接被关闭应用程序仍然在后台,只要你调用stop方法,GCDWebServer将自己暂停并停止接收新的连接。(这种行为可以通过GCDWebServerOption_AutomaticallySuspendInBackground选项禁用)。

2.如果应用程序切换到后台并且没有HTTP连接是打开的,只要你调用stop方法,GCDWebServer将立即暂停和停止接收新的连接。(这种行为可以与GCDWebServerOption_AutomaticallySuspendInBackground选项禁用)。

3.如果应用程序切换回到前台,而GCDWebServer已经暂停,只要你调用start方法,它会自动恢复,开始再次接收新的HTTP连接。

HTTP连接往往以包的形式开始向外并发,例如加载一个有多资源的网页。这使得它很难准确地检测出最后的HTTP连接已关闭:很有可能2个属于同一个分包但连续的HTTP连接将被一个短暂的延迟而非重叠分离。如果客户端刚好在两个连接之间的延迟部分挂起,这将会使问题变得很糟糕。GCDWebServerOption_AutomaticallySuspendInBackground选项可以优雅地解决这个问题,通过在最后一个HTTP连接关闭后强迫GCDWebServer等待一个额外的延迟,防止一个新的连接在延迟期间被分离。

GCDWebServer中的日志


为实现调试和查看信息,每当发生什么时,GCDWebServer都会对当前的服务状态进行日志记录。此外,当使用debug模式而不是release模式构建GCDWebServer,它将记录下更多的信息,也进行了大量的内部一致性检查。为了实现这一行为,编译GCDWebServer时指定预处理器常量 DEBUG =1。在Xcode的目标设置中,也可以通过增加DEBUG = 1到编译设置GCC_PREPROCESSOR_DEFINITIONS中。最后,你还可以在运行时调用+[GCDWebServer setLogLevel:]方法实现对冗长的日志进行进行控制。

默认情况下,所有通过GCDWebServer记录的日志都会被发送到其内置的日志中心,它只是输出到stderr(假设一个终端类型设备已连接)。为了更好地融入你的应用程序的其余部分或由于记录的信息量较大,你可能希望使用另一个日志记录中心。

GCDWebServer自动支持XLFacility(GCDWebServer的作者实现,已开源)和CocoaLumberjack。如果他们是在同一个Xcode项目中, GCDWebServer自动使用它们而不是内置日志中心(更多细节见 GCDWebServerPrivate.h文件)。

当然,也支持自定义日志功能,更多信息见GCDWebServer.h。

应用实例1:实现HTTP请求重定向


下面是一个将’/’重定向到’/index.html’的例子,使用GCDWebServerResponse提供的非常好用的方法(这个方法将设置HTTP状态并自动定位头文件)

{code}

[self addHandlerForMethod:@"GET"

path:@"/"

requestClass:[GCDWebServerRequest class]

processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {

return [GCDWebServerResponse responseWithRedirect:[NSURL URLWithString:@"index.html" relativeToURL:request.URL]

permanent:NO];

}];


应用实例2:实现表单


实现一个HTTP的表单,你需要两个handlers:

1.GET处理handler不需要HTTP请求中的body信息,因此采用 GCDWebServerRequest类。该handler程序将生产一个包含一个简单的HTML表单响应。

2.POST处理handler需要HTTP请求中经过encode后的body信息中的表单值。幸运的是,GCDWebServer提供请求的类GCDWebServerURLEncodedFormRequest可自动解析这些信息。该处理程序只简单地从用户提交的表单中获取返回值。

[webServer addHandlerForMethod:@"GET"

path:@"/"

requestClass:[GCDWebServerRequest class]

processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {

NSString* html = @" \

\

\

Value: \

\

\

\

";

return [GCDWebServerDataResponse responseWithHTML:html];

}];

[webServer addHandlerForMethod:@"POST"

path:@"/"

requestClass:[GCDWebServerURLEncodedFormRequest class]

processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {

NSString* value = [[(GCDWebServerURLEncodedFormRequest*)request arguments] objectForKey:@"value"];

NSString* html = [NSString stringWithFormat:@"%@", value];

return [GCDWebServerDataResponse responseWithHTML:html];

}];

应用实例3:实现动态网页


GCDWebServer提供一个扩展的GCDWebServerDataResponse类,可以返回根据模板和一组变量(使用格式%变量%)生成的HTML内容。这是一个非常基础的模板系统,作为一个起点引入,最终通过子类GCDWebServerResponse实现更高级的模板系统。

假设你有一个网站目录在你的应用程序中,包含HTML模板文件及相应的CSS,脚本和图片,那么,把它变成一个动态网站将会跟容易:

{code}

// Get the path to the website directory

NSString* websitePath = [[NSBundle mainBundle] pathForResource:@"Website" ofType:nil];

// Add a default handler to serve static files (i.e. anything other than HTML files)

[self addGETHandlerForBasePath:@"/" directoryPath:websitePath indexFilename:nil cacheAge:3600 allowRangeRequests:YES];

// Add an override handler for all requests to "*.html" URLs to do the special HTML templatization

[self addHandlerForMethod:@"GET"

pathRegex:@"/.*\.html"

requestClass:[GCDWebServerRequest class]

processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {

NSDictionary* variables = [NSDictionary dictionaryWithObjectsAndKeys:@"value", @"variable", nil];

return [GCDWebServerDataResponse responseWithHTMLTemplate:[websitePath stringByAppendingPathComponent:request.path]

variables:variables];

}];

// Add an override handler to redirect "/" URL to "/index.html"

[self addHandlerForMethod:@"GET"

path:@"/"

requestClass:[GCDWebServerRequest class]

processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {

return [GCDWebServerResponse responseWithRedirect:[NSURL URLWithString:@"index.html" relativeToURL:request.URL]

permanent:NO];

];

{code}

虽然可嵌入app的轻量级服务器还有CocoaHTTPServer,简单试用下就可以明显发现,GCDWebServer更加适合。

上一篇下一篇

猜你喜欢

热点阅读