zoukankan      html  css  js  c++  java
  • IOS学习笔记 -- 网络编程

    一.HTTP协议
    1.面试题: 聊一下HTTP协议(表达对HTTP协议的看法)
    * HTTP协议的全称: 超文本传输协议, 定制传输数据的规范(客户端和服务器之间的数据传输规范)
    * 描述HTTP协议完整的通信过程

    2.通信过程
    1> 请求
    * 客户端 --> 服务器
    * 请求的内容
    a."请求行" : 请求方法请求资源路径HTTP协议版本
    GET /MJServer/login?username=123&pwd=123&method=get&type=JSON HTTP/1.1

    b."请求头" : 客户端的信息
    Host: 192.168.1.200:8080
    User-Agent: iPhone Simulator; iPhone OS 7.1; en_US
    Accept: text/html
    Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
    Accept-Encoding: gzip, deflate

    c."请求体" : POST请求才需要有, 存放具体数据
    * 比如文件数据
    * 比如POST请求的参数数据

    2> 响应
    * 服务器 --> 客户端
    * 响应的内容
    a."状态行" : HTTP协议版本状态码状态信息, 也可称为"响应行"
    HTTP/1.1 200 OK

    b."响应头" : 服务器信息返回数据的类型返回数据的长度
    Server: Apache-Coyote/1.1
    Content-Type: application/json;charset=UTF-8
    Content-Length: 248

    c."实体内容" : 返回给客户端的具体内容, 也可称为"响应体"
    * 比如服务器返回的JSON数据
    * 比如服务器返回的文件数据

    3.HTTP请求的方法
    1> GET
    * 参数都拼接在URL后面
    * 参数有限制

    2> POST
    * 参数都在请求体
    * 参数没有限制
    * 文件上传只能用POST

    3> HEAD : 获得响应头信息, 不获取响应体

    4.iOS中发送GETPOST请求的手段
    1> NSURLConnection
    * 苹果原生
    * 使用起来, 比ASIAFN复杂

    2> ASI
    * 基于CFNetwork
    * 提供了非常多强大的功能, 使用简单

    3> AFN
    * 基于NSURLConnection
    * 提供了常用的功能, 使用简单

    4> 建议
    * 为了提高开发效率和减少调试花费的时间, 尽量使用著名的简单的第三方框架
    * 因此, 处理HTTP请求, 更建议使用ASI后者AFN

    二.NSURLConnection
    1.发送请求
    1> 发送一个同步请求
    + (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error;

    2> 发送一个异步请求(block)
    + (void)sendAsynchronousRequest:(NSURLRequest*) request
    queue:(NSOperationQueue*) queue
    completionHandler:(void (^)(NSURLResponse* response, NSData* data, NSError* connectionError)) handler;

    3> 发送一个异步请求(代理方法)
    [NSURLConnection connectionWithRequest:request delegate:self];
    [[NSURLConnection alloc] initWithRequest:request delegate:self];
    [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];

    NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
    [conn start];

    2.文件下载(大文件下载)
    1> 实现方案 : 边下载边写入(写到沙盒的某个文件中)
    2> 具体实现步骤
    a. 在接收到服务器的响应时
    // 创建一个空文件 - NSFileManager
    [mgr createFileAtPath:self.destPath contents:nil attributes:nil];

    // 创建一个跟空文件相关联的句柄对象 - NSFileHandle
    [NSFileHandle fileHandleForWritingAtPath:self.destPath];

    b. 在接收到服务器的数据时
    // 利用句柄对象将服务器返回的数据写到文件的末尾
    // 移动到文件的尾部
    [self.writeHandle seekToEndOfFile];
    // 从当前移动的位置(文件尾部)开始写入数据
    [self.writeHandle writeData:data];

    c. 在接收完服务器返回的数据时
    // 关闭句柄
    [self.writeHandle closeFile];
    self.writeHandle = nil;

    3.断点下载
    1> 关键技术点
    * 设置请求头Range, 告诉服务器下载哪一段数据

    4.文件上传
    1> 明确
    * 只能用POST请求
    * 请求参数都在请求体(文件参数非文件类型的普通参数)

    2> 实现步骤
    a. 拼接请求体(文件参数非文件类型的普通参数)
    * 文件参数
    // 参数的开始标记(分割线)
    --heima
    // 参数描述(参数名...)
    Content-Disposition: form-data; name="参数名"; filename="文件名"
    // 文件类型
    Content-Type: 文件的类型MIMEType
    // 文件的二进制数据(参数值)

    文件的二进制数据

    * 非文件参数(普通参数)
    // 参数的开始标记(分割线)
    --heima
    // 参数描述(参数名...)
    Content-Disposition: form-data; name="参数名"
    // 参数值

    参数值

    * 所有参数结束的标记
    --heima--

    b. 设置请求头
    * 请求体的长度
    Content-Length : 请求体的长度(字节长度)

    * 请求数据的类型
    Content-Type :
    // 普通POST请求: application/x-www-form-urlencoded
    // 上传文件的POST请求 : multipart/form-data; boundary=--heima

    5.JSON和XML
    1>.JSON 转换为 OC数据类型
    在iOS中,JSON的常见解析方案有4种
    第三方框架:JSONKit、SBJson、TouchJSON(性能从左到右,越差)
    苹果原生(自带):NSJSONSerialization(性能最好)
    NSJSONSerialization的常见方法
    JSON数据 -> OC对象
    + (id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error;
    OC对象 -> JSON数据
    + (NSData *)dataWithJSONObject:(id)obj options:(NSJSONWritingOptions)opt error:(NSError **)error;
    2>.XML 转换为 OC数据类型
    XML的解析方式有2种
    DOM:一次性将整个XML文档加载进内存,比较适合解析小文件
    SAX:从根元素开始,按顺序一个元素一个元素往下解析,比较适合解析大文件
    苹果原生
    NSXMLParser:SAX方式解析,使用简单
    第三方框架
    libxml2:纯C语言,默认包含在iOS SDK中,同时支持DOM和SAX方式解析
    GDataXML:DOM方式解析,由Google开发,基于libxml2
    a. NSXMLParser
    // 传入XML数据,创建解析器
    NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
    // 设置代理,监听解析过程
    parser.delegate = self;
    // 开始解析
    [parser parse];
    // NSXMLParserDelegate
    当扫描到文档的开始时调用(开始解析)
    - (void)parserDidStartDocument:(NSXMLParser *)parser
    当扫描到文档的结束时调用(解析完毕)
    - (void)parserDidEndDocument:(NSXMLParser *)parser
    当扫描到元素的开始时调用(attributeDict存放着元素的属性)
    - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
    当扫描到元素的结束时调用
    - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName

    三.NSURLCache
    缓存的使用步骤
    // 获得全局的缓存对象
    NSURLCache *cache = [NSURLCache sharedURLCache];

    // 设置缓存容量
    cache.memoryCapacity = 1024 * 1024;
    cache.diskCapacity = 20 * 1024 * 1024;

    // 设置请求的缓存策略
    request.cachePolicy = NSURLRequestReturnCacheDataElseLoad;

    四.ASI
    1.缓存的使用步骤
    1> 缓存单个请求
    // 1.获得全局的缓存对象(决定缓存的存储路径, 存储到什么地方)
    ASIDownloadCache *cache = [ASIDownloadCache sharedCache];
    // 设置默认的缓存加载策略
    cache.defaultCachePolicy = ASIDoNotReadFromCacheCachePolicy;

    // 2.设置请求对象的缓存对象(使用哪个缓存对象)
    request.downloadCache = cache;

    // 3.设置请求对象的缓存加载策略
    request.cachePolicy = ASIOnlyLoadIfNotCachedCachePolicy;
    // 如果没有缓存, 才发送请求

    // 4.设置请求对象的缓存存储策略(存储的时长)
    request.cacheStoragePolicy = ASICachePermanentlyCacheStoragePolicy;
    // 永久存储

    注意, 缓存加载策略的优先级 : request.cachePolicy > cache.defaultCachePolicy

    2> 缓存所有请求
    // 1.获得全局的缓存对象(决定缓存的存储路径, 存储到什么地方)
    ASIDownloadCache *cache = [ASIDownloadCache sharedCache];
    // 设置默认的缓存加载策略
    cache.defaultCachePolicy = ASIOnlyLoadIfNotCachedCachePolicy;

    // 2.设置全局缓存对象
    [ASIHTTPRequest setDefaultCache:cache];

    2.发送请求
    1> 同步请求
    [request startSynchronous];

    2> 异步请求
    [request startAsynchronous];

    3.GETPOST
    1> GET请求
    ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];

    2> POST请求
    ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
    // 添加普通参数(非文件参数)
    [request setPostValue:@"zhangsan" forKey:@"username"];
    [request setPostValue:@"123" forKey:@"pwd"];

    4.文件下载
    // 文件的存储路径(文件下载到什么地方)
    request.downloadDestinationPath = filepath;
    // 设置下载代理(监听下载进度)
    request.downloadProgressDelegate = self.circleView;
    // 支持断点下载
    request.allowResumeForFileDownloads = YES;

    5.文件上传
    // 添加文件参数(file : 需要上传文件的路径)
    [request setFile:file forKey:@"file"];
    [request setFile:file withFileName:@"123.txt" andContentType:@"text/plain" forKey:@"file"];
    [request setData:data withFileName:@"minion.png" andContentType:@"image/png" forKey:@"file"];

    // 设置上传代理(监听上传进度)
    request.uploadProgressDelegate = self.circleView;

    6.监听请求的过程
    1> 代理方法
    // 设置代理
    request.delegate = self;
    // 遵守协议
    ASIHTTPRequestDelegate
    // 实现协议中的代理方法
    - (void)requestStarted:(ASIHTTPRequest *)request;
    - (void)request:(ASIHTTPRequest *)request didReceiveData:(NSData *)data
    - (void)requestFinished:(ASIHTTPRequest *)request;
    - (void)requestFailed:(ASIHTTPRequest *)request;

    2> SEL
    // 设置代理
    request.delegate = self;
    // 设置方法名
    [request setDidStartSelector:@selector(start)]; // 开始发送请求, 就会调用代理的start方法
    // ....

    3> block
    [request setStartedBlock:^{
    NSLog(@"setStartedBlock ----");
    }];

    [request setDataReceivedBlock:^(NSData *data) {
    NSLog(@"setDataReceivedBlock ----");
    }];

    [request setCompletionBlock:^{
    NSLog(@"setCompletionBlock ----");
    }];

    [self setFailedBlock:^{
    NSLog(@"setFailedBlock ----");
    }];

    7.通过request对象获得服务器的响应
    1> 获得响应头信息
    @property (atomic, retain) NSDictionary *responseHeaders;

    2> 获得响应体(实体内容)
    - (NSData *)responseData; // 直接返回服务器的二进制数据
    - (NSString *)responseString; // 将二进制数据转成字符串(方便调试)

    五.AFN
    1.GETPOST
    1> GET请求
    // 1.获得请求管理者
    AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];

    // 2.封装请求参数
    NSMutableDictionary *params = [NSMutableDictionary dictionary];
    params[@"username"] = @"123";
    params[@"pwd"] = @"123";

    // 3.发送GET请求
    [mgr GET:@"http://192.168.1.200:8080/MJServer/login" parameters:params
    success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSLog(@"请求成功---%@", responseObject);
    }
    failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"请求失败---%@", error);
    }];


    2> POST请求
    // 1.获得请求管理者
    AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];

    // 2.封装请求参数
    NSMutableDictionary *params = [NSMutableDictionary dictionary];
    params[@"username"] = @"123";
    params[@"pwd"] = @"123";

    // 3.发送POST请求
    [mgr POST:@"http://192.168.1.200:8080/MJServer/login" parameters:params
    success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSLog(@"请求成功---%@", responseObject);
    }
    failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"请求失败---%@", error);
    }];

    2.文件上传
    // 1.获得请求管理者
    AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];

    // 2.发送请求(做文件上传)
    #warning parameters : 只能放非文件参数
    NSMutableDictionary *params = [NSMutableDictionary dictionary];
    params[@"username"] = @"zhangsan";

    [mgr POST:@"http://192.168.1.200:8080/MJServer/upload" parameters:params
    constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
    // 一定要在这个block中添加文件参数

    // 加载文件数据
    NSString *file = [[NSBundle mainBundle] pathForResource:@"test.txt" ofType:nil];
    NSData *data = [NSData dataWithContentsOfFile:file];

    // 拼接文件参数
    [formData appendPartWithFileData:data name:@"file" fileName:@"123.txt" mimeType:@"text/plain"];
    }
    success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSLog(@"上传成功----%@", responseObject);
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"上传失败----%@", error);
    }];

    六.网络状态监控
    1.Reachability
    // 监听网络状态改变的通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkStateChange) name:kReachabilityChangedNotification object:nil];

    // 创建Reachability
    self.conn = [Reachability reachabilityForInternetConnection];
    // 开始监控网络(一旦网络状态发生改变, 就会发出通知kReachabilityChangedNotification)
    [self.conn startNotifier];

    // 处理网络状态改变
    - (void)networkStateChange
    {
    // 1.检测wifi状态
    Reachability *wifi = [Reachability reachabilityForLocalWiFi];

    // 2.检测手机是否能上网络(WIFI3G2.5G)
    Reachability *conn = [Reachability reachabilityForInternetConnection];

    // 3.判断网络状态
    if ([wifi currentReachabilityStatus] != NotReachable) { // 有wifi
    NSLog(@"有wifi");
    } else if ([conn currentReachabilityStatus] != NotReachable) { // 没有使用wifi, 使用手机自带网络进行上网
    NSLog(@"使用手机自带网络进行上网");
    } else { // 没有网络
    NSLog(@"没有网络");
    }
    }

    2.AFN
    // 1.获得网络监控的管理者
    AFNetworkReachabilityManager *mgr = [AFNetworkReachabilityManager sharedManager];

    // 2.设置网络状态改变后的处理
    [mgr setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
    // 当网络状态改变了, 就会调用这个block
    switch (status) {
    case AFNetworkReachabilityStatusUnknown: // 未知网络
    NSLog(@"未知网络");
    break;

    case AFNetworkReachabilityStatusNotReachable: // 没有网络(断网)
    NSLog(@"没有网络(断网)");
    break;

    case AFNetworkReachabilityStatusReachableViaWWAN: // 手机自带网络
    NSLog(@"手机自带网络");
    break;

    case AFNetworkReachabilityStatusReachableViaWiFi: // WIFI
    NSLog(@"WIFI");
    break;
    }
    }];

    // 3.开始监控
    [mgr startMonitoring];

    七.ASI和AFN有什么区别
    1.性能(重点)
    * ASI基于底层的CFNetwork框架
    * AFN基于NSURLConnection
    * 运行性能: ASI > ASN

    2.处理服务器数据
    1> AFN : 根据服务器返回数据的数据, 进行自动解析
    * 服务器返回的是JSON数据, 自动转换为NSDictionary或者NSArray
    * 服务器返回的是XML数据, 自动转换为NSXMLParser

    2> ASI : 并没有对服务器的数据进行解析, 直接返回NSData二进制数据

    3.处理请求的过程
    1> AFN : success和failure两个block
    2> ASI : 有3种方式处理请求过程(代理方法SELlock)

    3.ASI的特色(重点)
    1> 缓存

    2> 下载和上传
    * 轻松监听请求进度
    * 轻松实现断点下载(ASI没有断点上传功能, 断点上传得使用socket技术)

    3> 提供了很多扩展接口(比如做数据压缩)
    * ASIDataCompressor.h
    * ASIDataDecompressor.h

    4> ASIHttpRequest继承自NSOperation
    * 能用队列统一管理所有请求
    * 请求之间能依赖

    5> ASINetworkQueue
    * 统一管理所有请求
    * 5个下载上传请求 --> ASINetworkQueue : 监听5个请求的总进度
    * 监听所有请求的开始失败完毕
    * shouldCancelAllRequestsOnFailure
    YES : 队列中某个请求失败了, 其他所有请求都取消
    NO : 队列中的某个请求失败了, 其他请求不受影响, 继续请求

    4.AFN的特色
    1> 使用简单
    2> 自带了网络监控功能

  • 相关阅读:
    Linux常用命令2
    Linux常用命令1
    Nginx配置Kafka
    SpringBoot整合Druid
    spring boot jpa
    mybatis-plus_2
    copy data to map
    HashMap容量问题
    在SpringBoot主启动类中获取实例化的Bean
    Linux环境中Rsync增量备份文件
  • 原文地址:https://www.cnblogs.com/wentianblog/p/3820749.html
Copyright © 2011-2022 走看看