01-网络入门

2017-08-27  本文已影响27人  AlanGe

一、网络基础知识介绍

1、为什么要学习网络编程?

在移动互联网时代,移动应用的特征有
几乎所有应用l都需要用到网络,比如QQ、微博、网易新闻、优酷、百度地图
只有通过网络跟外界进行数据交互、数据更新,应用才能保持新鲜、活力
如果没有了网络,也就缺少了数据变化,无论外观多么华丽,终将变成一潭死水

移动网络应用 = 良好的UI + 良好的用户体验 + 实时更新的数据
新闻:网易新闻、新浪新闻、搜狐新闻、腾讯新闻
视频:优酷、百度视频、搜狐视频、爱奇艺视频
音乐:QQ音乐、百度音乐、酷狗音乐、酷我音乐
LBS:百度地图、高德地图、大众点评、墨迹天气、滴滴打车
电商:淘宝、京东商城、天猫、蘑菇街、凡客诚品、美丽说
社交:QQ、微信、微博、陌陌、比邻

为什么要学习网络编程
网络编程是一种实时更新应用数据的常用手段
网络编程是开发优秀网络应用的前提和基础

2、网络编程示例

PC互联网和移动互联网

移动互联网,就是将移动通信和互联网二者结合起来,成为一体。是指互联网的技术、平台、商业模式和应用与移动通信技术结合并实践的活动的总称。
PC互联网:即传统的互联网,将计算机网络互相联接在一起的方法可称作“网络互联”,在这基础上发展出覆盖全世界的全球性互联网络称互联网。

PC互联网和移动互联网的区别:

字面理解:一个是移动的互联网,一个是固定的互联网,这是相对而言的。
终端设备的区别:移动互联网主要有智能手机,而PC互联网主要是计算机。
形态:移动互联网则釆用客户端APP结构加通信录为主,PC互联网采用B/S结构为主,也就是浏览器、服务器结构。

3、基本概念

作为移动开发工程师,主要的精力都是放在前端开发


4、服务器分类

二、HTTP 介绍

1、URL和常见协议
2、HTTP协议简介
3、HTTP协议的作用
4、HTTP协议的特点
5、HTTP的基本通信过程

三、网络开发解决方案

1、苹果原生方案
2、第三方框架

建议:为了提高开发效率,企业开发用的基本是第三方框架

//  ViewController.m
//  01-NSURLConnection访问百度

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    // URL : 确定要访问的资源路径
    // m:mobile 一般大公司会提供专门给手机上使用的网址
    NSURL *url = [NSURL URLWithString:@"http://m.baidu.com"];
    
    // NSURLRequest: 根据URL创建请求对象
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    //NSURLConnection:发送请求 向服务器索要数据
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
        
        // 将二进制数据转换成字符串
        // 一般在实际开发中,如果没有特殊要求,编码方式统一使用UTF8
        // UNICODE一种编码方式 UTF8使用1到4个字节表示一个文字. 一个汉字占3个字节来表示. 大约43亿  能够表示完全世界的文字.
        // GBK:国标 1980年颁发的汉字库  6700+个文字  中国现在大约有100000+
        NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        
        NSLog(@"%zd--%@",data.length,result);
    }];
    
}

@end

用 webView显示

//  ViewController.m
//  02-NSURLConnection显示百度-(掌握)

#import "ViewController.h"

@interface ViewController ()
    
@property (weak, nonatomic) IBOutlet UIWebView *webView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self loadData];
}
    
- (void)loadData {
    // URL : 确定要访问的资源路径
    // m:mobile 一般大公司会提供专门给手机上使用的网址
    NSURL *url = [NSURL URLWithString:@"http://m.baidu.com"];
    
    // NSURLRequest: 根据URL创建请求对象
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    //NSURLConnection:发送请求 向服务器索要数据
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
        
        // 将二进制数据转换成字符串
        // 一般在实际开发中,如果没有特殊要求,编码方式统一使用UTF8
        // UNICODE一种编码方式 UTF8使用1到4个字节表示一个文字. 一个汉字占3个字节来表示. 大约43亿  能够表示完全世界的文字.
        // GBK:国标 1980年颁发的汉字库  6700+个文字  中国现在大约有100000+
        NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        
        // 显示界面
        //baseURL:加载资源的参照路径
        [self.webView loadHTMLString:result baseURL:url];
        NSLog(@"%zd--%@",data.length,result);
    }];
}

@end

//  ViewController.m
//  03-请求参数详解和缓存策略以及超时时长-(掌握)

#import "ViewController.h"

@interface ViewController ()
    
@property (weak, nonatomic) IBOutlet UIWebView *webView;

@end

@implementation ViewController
    
    
- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self loadData];
}
    
    
- (void)loadData {
    // URL : 确定要访问的资源路径
    // m:mobile 一般大公司会提供专门给手机上使用的网址
    NSURL *url = [NSURL URLWithString:@"http://m.baidu.com/"];
    
    // NSURLRequest: 根据URL创建请求对象
    //    User-Agent    Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/601.2.7 (KHTML, like Gecko) Version/9.0.1 Safari/601.2.7
    
    /*
     cachePolicy 缓存策略
         NSURLRequestUseProtocolCachePolicy = 0, 默认的缓存策略
         
         一般对实时性要求比较高的应用,比如12306,彩票,股票...
         NSURLRequestReloadIgnoringLocalCacheData = 1, 忽略本地缓存数据,直接从服务器上拿数据.
         
         一般使用在做离线开发
         本地数据库,sqlite3数据库.
         NSURLRequestReturnCacheDataElseLoad = 2, 有缓存就返回缓存数据,没有就加载.
         NSURLRequestReturnCacheDataDontLoad = 3, 有缓存就返回缓存数据,否则不加载.
     
     timeoutInterval:请求超时时长. 在指定的时间内,如果还没有获得服务器响应.则认为本次是失败的.
         - 默认超时时长是60s 建议不要太快,也不要太慢 一般建议到15s-30s
     */
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:15];
    
    
    // 通过request对象告诉服务器一些额外的信息
    // 通过请求头告诉服务器我是xxx
//    [request setValue:@"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/601.2.7 (KHTML, like Gecko) Version/9.0.1 Safari/601.2.7" forHTTPHeaderField:@"User-Agent"];
    
    // 告诉服务器我是iphone 并且支持苹果的网页套件
    [request setValue:@"iPhoneWebKit" forHTTPHeaderField:@"User-Agent"];
    
    //NSURLConnection:发送请求 向服务器索要数据
    /**
     sendAsynchronousRequest:方法内部会自动创建一个线程来做异步请求.
     
     completionHandler:当接收到服务器响应时调用.
     queue:决定completionHandler在主线程还是在子线程执行.
     
     如何选择队列?
     - 如果获得服务器响应之后直接更新UI,则选择主队列.
     - 如果获得响应后,要做耗时操作,则选择创建队列.比如下载zip文件,解压缩
     
     重定向:
     response: 本质是NSHTTPURLResponse对象
         - URL: 响应的URL,一般使用在有重定向的界面,如果没有重定向,则请求URL和响应URL是一样的
         - MIMEType: 服务器告诉客户端返回的数据类型是什么.
         - Content-Type: 等价于MIMEType
         - textEncodingName: 服务器告诉客户端返回内容编码方式
         - allHeaderFields: 响应头信息.服务器返回给客户端的额外信息
         
         // 下面三个必须记住
         --- 下面两个属性一般使用在开发下载功能
         - expectedContentLength: 服务器告诉客户端返回数据的长度.
         - suggestedFilename: 服务器建议客户端保存文件使用的文件名
         - statusCode : 状态码
     */
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
        
        //将父类response的强转为子类型才能点得出allHeaderFields
        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
        NSLog(@"%@--",httpResponse.allHeaderFields);
        
        // 在实际开发中一定要对错误进行处理,因为所有的网络请求都有可能出错. 比如没有流量,没有信号,手机没钱
        // connectionError如果不为nil,则表示有错了,提示用户出错了,但不要提示得太专业.
        // 404表示请求的资源不存在
        // data:服务器返回的二进制数据
        // 客户端和服务器之间传输数据都是二进制数据.
        if(connectionError != nil || data.length == 0) {
            NSLog(@"亲.你的网络不给力喔");
            return;
        }
        
        [self.webView loadRequest:[NSURLRequest requestWithURL:response.URL]];
        
        
        // 将二进制数据转换成字符串
        // 一般在实际开发中,如果没有特殊要求,编码方式统一使用UTF8
        // UNICODE一种编码方式 UTF8使用1到4个字节表示一个文字. 一个汉字占3个字节来表示. 大约43亿  能够表示完全世界的文字.
        // GBK:国标 1980年颁发的汉字库  6700+个文字  中国现在大约有100000+
//        NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
//        // 显示界面
//        //baseURL:加载资源的参照路径
//        [self.webView loadHTMLString:result baseURL:url];
//        NSLog(@"%zd--%@",data.length,result);
    }];
    
}
  
@end

重定向—用苹果浏览器打开到mac系统页面是由于浏览器的用户代理-User-Agent会告诉服务器是用什么类型的系统

四、NSURLConnection常用方法

使用步骤
1、代码演示--访问百度
// 1、NSURL :确定要访问的资源路径
// m:mobile 代表手机上访问的路径,一般大公司都会提供一个专门手机上访问的路径
NSURL *url = [NSURL URLWithString:@"http://m.baidu.com/"];
// 2、NSURLRequest:根据 url 创建请求对象,向服务器索要数据
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 3、建立网络链接,将请求(同步或异步)发送给服务器
[NSURLConnection sendAsynchronousRequest:reuqest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
    
    /*
     编码:在日常开发中,如果没有特殊原因,编码统一使用‘UTF8’
     - UTF8 :是 UNICODE的一种编码方式,使用 1到4个字节表述一个字符,能够表述全世界的所有的字符
     - GB2312:国标,1980年颁布的汉字库,6700+汉字,只有一些老的网站还在使用
     现在中文汉字大约:100000+
     */
    NSString *html = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"%@",html);
}];
2、UIWebView显示百度首页

开发中服务器返回的都是字符串数据,下面利用UIWebView加载请求百度返回的字符串---显示百度首页。

// 1、NSURL :确定要访问的资源路径
NSURL *url = [NSURL URLWithString:@"http://m.baidu.com/"];
// 2、NSURLRequest:根据url创建请求对象,向服务器索要数据
NSMutableURLRequest *reuqest = [NSMutableURLRequest requestWithURL:url];
// 2.1、告诉服务器额外的信息
// iPhone: 告诉服务器我是 iPhone
// iPhone AppleWebKit":告诉服务器我是 iPhone,并且要支持苹果的网页套件
[reuqest setValue:@"iPhone AppleWebKit" forHTTPHeaderField:@"User-Agent"];
// 3、建立网络链接,将请求(同步或异步)发送给服务器
[NSURLConnection sendAsynchronousRequest:reuqest queue:[NSOperationQueue  mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
    // 将二进制数据转换成字符串
    NSString *html = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    // baseURL:加载资源的参照路径。
    [self.webView loadHTMLString:html baseURL:url];
}];
3、服务器响应演练
- (void)loadData{
    // 1. 创建 url
    NSURL *url = [NSURL URLWithString:@"http://pinyin.sogou.com/"];
    // 2. 创建请求对象
    //    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setValue:@"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36" forHTTPHeaderField:@"User-Agent"];
    // 3. 发送异步请求到服务器(所有的网络请求都是耗时操作,因此绝大多数都是异步请求)
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        NSLog(@"%@---%@--%@---%@----%@",response,response.MIMEType,response.URL,response.textEncodingName,response.suggestedFilename);
        [self.webView loadData:data MIMEType:response.MIMEType textEncodingName:response.textEncodingName baseURL:url];
    }];
}

参数解释:
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
    * response:本质上就是NSHTTPURLResponse从服务器上获得的响应。
    * NSURLResponse相关属性:
    * URL:响应url,一般用来重定向使用。浏览器演示什么是重定向,百度搜索 搜狗输入法。(没有重定向的情况下,响应url和请求url是相同)
    * MIMEType:请求数据的数据类型,服务器告诉客户端的返回的数据是什么类型。
    * Content-Type等价MIMEType,客户端根据MIMEType决定用什么来打开或显示返回的数据。
    * (典型的例子就是浏览器装flash插件的例子。当在浏览器中看视频的时候,浏览器都会提示要安装flash插件,否则无法观看,浏览器就是通过MIMEType来判断观看视频需要flash插件的支持。)
    * textEncodingName:返回内容的编码方式
    
    
    * 以下两个属性通常用于开发下载
    * expectedContentLength:请求二进制数据的长度,下载文件的大小。
    * suggestedFilename:建议保存的文件名,服务器建议下载文件保存时使用的文件名,一般mac下下载文件不需要填写保存的文件名,就是因为浏览器客户端根据服务器返回的该字段作为文件名了。
// 有时候没有错误,但也没有数据
if (connectionError != nil || data == nil) {

    //提示用户最好友善点,不要太专业了。比如提示出现404错误,或500错误了。用户不会理解这些专业术语的。
    NSLog(@"你的网络不给力哦!");

    return ;
}

在菜单栏中显示“开发”菜单

五、Socket 编程

1、简介
2、辅助工具---NetCat

1、网络通讯三要素

1.1、电话图

2、Socket的建立和连接

#import <sys/socket.h>
#import <netinet/in.h>
#import <arpa/inet.h> 
/**
 参数
 domain:    协议域/协议族,AF_INET(IPV4的网络开发)
 type:      Socket 类型,SOCK_STREAM(TCP)/SOCK_DGRAM(UDP,报文)
 protocol:  IPPROTO_TCP,协议,如果输入0,可以根据第二个参数自动选择协议
 
 返回值
 socket,如果>0 就表示成功
 */
int clientSocket = socket(AF_INET, SOCK_STREAM, 0);
/**
 参数
 1> 客户端socket
 2> 指向数据结构sockaddr的指针,其中包括目的端口和IP地址。即服务器的“结构体”地址
 3> 结构体数据长度
 返回值
 0 成功/其他 错误代号,非0即真
 */
struct sockaddr_in serverAddress;
// 协议族
serverAddress.sin_family = AF_INET;
// ip 找机器
serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1");
// 端口号 找程序
serverAddress.sin_port = htons(12345);
// 连接服务器
int result =  connect(clientSocket, (const struct sockaddr *)&serverAddress, sizeof(serverAddress));
if (result == 0) {
    NSLog(@"成功");
} else {
    NSLog(@"失败");
}

友情提示
在C语言开发时,如果要传递结构体的地址,通常会一起传递结构的长度。因为 C 语言中取数据是通过指针寻址的,告诉长度的目的是防止取错数据。
在终端输入:nc -lk 12345 相当于在本机上启动了一个服务器,ip是本机地址,端口号是12345。

3、发送和接收数据

/**
 参数
 1> 客户端socket
 2> 发送内容地址 void * == id
 3> 发送内容长度,是指字节的长度。
 4> 发送方式标志,一般为0
 返s回值
 如果成功,则返回发送的字节数,失败则返回SOCKET_ERROR
 */
NSString *msg = @"约?";
ssize_t sendLenght =  send(clientSocket, msg.UTF8String, strlen(msg.UTF8String), 0);
NSLog(@"发送了%ld长度的字节,字符串长度%zd",sendLenght,msg.length);
/**
     参数
     1> 客户端socket
     2> 接收内容地址
     3> 长度,表示一次最多接收服务器返回的多少字节内容。
     4> 接收标志,一般填0,表示阻塞式的,一直等待服务器返回数据
     返回值
     接收数据的长度
     */
    // 缓冲区,准备接受来自服务器的数据
    // C语言中,数组的名字,就是指向数组第一个元素的指针。
    uint8_t buffer[1024];
    ssize_t recvLen = recv(clientSocket, buffer, sizeof(buffer), 0);
    NSLog(@"接收 %ld 字节",recvLen);
    // 获得服务器返回的二进制数据
    NSData *data = [NSData dataWithBytes:buffer length:recvLen];
    // 将二进制数据转化成字符串
    NSString *resultStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"接收到的内容是:%@",resultStr);

4、关闭连接

断开连接
close(clientSocket);

5、htons函数的作用

六、Socket 聊天示例

#import "ViewController.h"
#import <sys/socket.h>
#import <netinet/in.h>
#import <arpa/inet.h>
@interface ViewController ()
/**
 *  主机
 */
@property (weak, nonatomic) IBOutlet UITextField *hostField;
/**
 *  端口
 */
@property (weak, nonatomic) IBOutlet UITextField *portField;
/**
 *  消息
 */
@property (weak, nonatomic) IBOutlet UITextField *msgField;
/**
 *  内容
 */
@property (weak, nonatomic) IBOutlet UILabel *recvLabel;

/**
 * 客户端 socket
 */
@property(nonatomic,assign) int  clientSocket;
@end

@implementation ViewController
/**
 *  监听连接按钮
 */
- (IBAction)connection {
    BOOL result = [self connectionToHost:self.hostField.text port:self.portField.text.integerValue];
    self.recvLabel.text = result ? @"成功":@"失败";
}

/**
 *  监听发送按钮
 */
- (IBAction)send{
    self.recvLabel.text = [self sendAndRecv:self.msgField.text];
    [self disconnection];
}

- (void)viewDidLoad {
    [super viewDidLoad];
}

/**
 *  连接服务器
 */
- (BOOL)connectionToHost:(NSString *)host port:(NSInteger)port{
    // 1.创建 socket
    /**
     参数
     
     domain:    协议域/协议族,AF_INET(IPV4的网络开发)
     type:      Socket 类型,SOCK_STREAM(TCP)/SOCK_DGRAM(UDP,报文)
     protocol:  IPPROTO_TCP,协议,如果输入0,可以根据第二个参数自动选择协议
     
     返回值
     socket,如果>0 就表示成功

*/
     self.clientSocket = socket(AF_INET, SOCK_STREAM, 0);
    // 2.连接
    /**
     参数
     1> 客户端socket
     2> 指向数据结构sockaddr的指针,其中包括目的端口和IP地址。即服务器的“结构体”地址
     3> 结构体数据长度
     返回值
     0 成功/其他 错误代号,非0即真
     */
    struct sockaddr_in serverAddress;
    // 协议族
    serverAddress.sin_family = AF_INET;
    // ip 找机器 inet_addr内部会对地址做字节翻转
    serverAddress.sin_addr.s_addr = inet_addr(host.UTF8String);
    //
    // 端口号 找程序
    serverAddress.sin_port = htons(port);
    // 连接服务器
    return (connect(self.clientSocket, (const struct sockaddr *)&serverAddress, sizeof(serverAddress)) == 0);
    
}

/**
 *  发送和接收
 */
- (NSString *)sendAndRecv:(NSString *)msg{
    // 发送数据
    /**
     参数
     1> 客户端socket
     2> 发送内容地址 void * == id
     3> 发送内容长度,是指字节的长度。
     4> 发送方式标志,一般为0
     返回值
     如果成功,则返回发送的字节数,失败则返回SOCKET_ERROR
     */
    ssize_t sendLenght =  send(self.clientSocket, msg.UTF8String, strlen(msg.UTF8String), 0);
    NSLog(@"发送了%ld长度的字节,字符串长度%zd",sendLenght,msg.length);
    
    // 接收数据
    /**
     参数
     1> 客户端socket
     2> 接收内容地址
     3> 长度,表示一次最多接收服务器返回的多少字节内容。
     4> 接收标志,一般填0,标示阻塞式的,一直等待服务器服务器返回数据
     返回值
     接收数据的长度
     */
    // 缓冲区,准备接受来自服务器的数据
    // C语言中,数组的名字,就是指向数组第一个元素的指针。
    uint8_t buffer[1024];
    ssize_t recvLen = recv(self.clientSocket, buffer, sizeof(buffer), 0);
    NSLog(@"接收 %ld 字节",recvLen);
    // 获得服务器返回的二进制数据
    NSData *data = [NSData dataWithBytes:buffer length:recvLen];
    // 将二进制数据转化成字符串
    return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

}

/**
 *  断开连接
 */
- (void)disconnection{
    close(self.clientSocket);
}
@end

七、通信过程

1、Socket发送HTTP请求本地apache服务器

// 建立连接
if (![self connectionToHost:@"127.0.0.1" port:80]) {

    NSLog(@"失败");

    return;

}

NSLog(@"成功");

// 向服务器发送请求数据
NSString *result =  [self sendAndRecv:@"我要成为牛逼的程序员"];
NSLog(@"%@",result);

提问:给服务器发送的数据,服务器能接收到吗?会有响应结果吗?
答:能接收到数据,但是不会有任何响应结果。原因是服务器不知道客户端发送的内容是什么。
思考
1)、客户端该传什么格式的数据给服务器?服务器才能看懂。
2)、服务器该返回什么格式的数据给客户端?客户端才能看懂。

// 向服务器发送请求数据
// 请求字符串,指定请求头和请求行
NSString *request = @"GET /abcd.txt HTTP/1.1\r\n""Host:localhost\r\n\r\n";
/**
URL与请求的对应关系:
比如URL是:[http://localhost/abcd.txt](http://localhost/abcd.txt) 其中协议头 http是由HTTP/1.1指定的,主机地址是由Host:localhost指定的,路径是由/abcd.txt指定的

*/
NSString *result =  [self sendAndRecv:request];

NSLog(@"%@",result);

2、Socket发送HTTP请求远程服务器(百度,京东,起点)

/***  连接远程服务器(百度,京东,起点) */
- (void)connectionToRometionServer{
        
    // 百度:域名 [m.baidu.com](http://m.baidu.com/) ip:61.135.185.17
    // 起点:域名 [m.qidian.com](http://m.qidian.com/)  ip:36.250.76.204
    // 京东:域名 [m.jd.com](http://m.jd.com/) ip:111.206.227.150
 
    // 建立连接
    if (![self connectionToHost:@"111.206.227.150" port:80]) {
        NSLog(@"失败");
        return;
    }
 
    NSLog(@"成功");
  
    // 向服务器发送请求数据
    NSString *request = @"GET / HTTP/1.1\r\n"
    "Host:m.jd.com\r\n"
    "User-Agent:iPhone AppleWebKit\r\n"
    "Connection:Close\r\n\r\n";

    NSString *result =  [self sendAndRecv:request];
  
    // 在返回结果中查找\r\n\r\n,目的是取出响应状态行和响应头的内容
    NSRange range = [result rangeOfString:@"\r\n\r\n"];
        
    if (range.location != NSNotFound) {
        NSString *html = [result substringFromIndex:range.location];
        NSLog(@"=======> %@",html);
            
        // 加载网页
        [self.webView loadHTMLString:html baseURL:[NSURL URLWithString:@"[http://m.jd.com](http://m.jd.com/)"]];
    }
    NSLog(@"--------%@",result);
}

友情提示
ping 域名; 就能得到对应网站的ip地址。

3、HTTP通信过程

1)、请求行:指定 请求方法、请求资源路径 以及 HTTP协议版本。
# / 表示访问根目录
GET / HTTP/1.1

2)、请求头:对客户端的环境描述、客户端请求的主机地址等信息。
*请求头中 至少包含以下信息
# 客户端要访问的服务器主机地址:Host:[m.baidu.com](http://m.baidu.com/)
                  
* 请求头中 还可以包含以下信息
# 客户端的类型,客户端的软件环境:User-Agent:iPhone AppleWebKit
# 客户端所能接收的数据类型:Accept:text/html
# 客户端的语言环境:Accept-Language:zh-cn
# 客户端支持的数据压缩格式:Accept-Encoding:gzip
# 访问结束后,是否断开连接:Connection:Close
                  
                  
3)、请求体(可选):客户端发给服务器的具体数据,例如要上传的文件数据。
请求格式:
○ 每一项请求信息末尾使用 \r\n
○ 最后一个请求项末尾使用 \r\n\r\n 表示请求结束
#warming 每一项请求信息和\r\n之间不能有空格。
1)、状态行:包含了HTTP协议版本、状态码、状态英文名称
    #HTTP/1.1 200 OK

2)、响应头:包含了对服务器的描述、对返回数据的描述
    #Server: Apache-Coyote/1.1 // 服务器的类型
    #Content-Type: image/jpeg // 返回数据的类型
    #Content-Length: 56811 // 返回数据的长度
    #Date: Mon, 23 Jun 2014 12:54:52 GMT // 响应的时间

3)、实体内容:服务器返回给客户端的具体数据,比如文件数据

八、Xcode网络适配

Xcode7 使用NSURLSession和 NSURLConnection发送HTTP请求报错
控制台打印:Application Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.
解决方法:
编辑 info.plist,加入如下设置:
<plist>
<dict>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
</dict>
</plist>

九、单例模式

单例模式的意思就是只有一个实例。单例模式确保某一个类只有一个实例,而且自行实例化并向整个应用提供这个实例。
这个类称为单例类。

1、ARC

(一般不用写)// 定义一个静态变量,在程序运行过程中只有1份(只加载一次)
 static id instance;
 - (instancetype)init {
         static id obj = nil;
         static dispatch_once_t onceToken;
         // 确保只执行一次初始化代码
         dispatch_once(&onceToken, ^{
                 if ((obj = [super init])) {
                         // 加载资源
                         NSLog(@"加载资源");
                     }
             });
         return obj;
 }
 
 // 重写这个方法控制内存只分配一次
 + (instancetype)allocWithZone:(struct _NSZone *)zone{
         static dispatch_once_t onceToken;
         // 里面的代码只会执行1次
         dispatch_once(&onceToken, ^{
                 instance = [super allocWithZone:zone];
             });
         // 返回对象
         return instance;
 }
 
 // 确保复制的对象还是同一个
 - (id)copyWithZone:(NSZone *)zone {
         return self;
 }
 
 // 全局访问点
 + (instancetype)sharedAudioTool {
         return [[self alloc] init];
 }

2、非ARC

// 定义一个静态变量,在程序运行过程中只有1份
static id instance;
- (instancetype)init {
    static id obj = nil;
    static dispatch_once_t onceToken;
    // 确保只执行一次初始化代码
    dispatch_once(&onceToken, ^{
        if ((obj = [super init])) {
            // 加载资源
            NSLog(@"加载资源");
        }
    });
    return obj;
}

// 重写这个方法控制内存只分配一次
+ (instancetype)allocWithZone:(struct _NSZone *)zone{
    static dispatch_once_t onceToken;
    // 里面的代码只会执行1次
    dispatch_once(&onceToken, ^{
        instance = [super allocWithZone:zone];
    });
    // 返回对象
    return instance;
}

// 确保复制的对象还是同一个
- (id)copyWithZone:(NSZone *)zone {
    return self;
}

// 全局访问点
+ (instancetype)sharedAudioTool {
    return [[self alloc] init];
}

#pragma mark - 在非 ARC 环境下要重写下面内存管理的方法
//oneway:是分布式对象的API,它允许不同的线程或应用程序之间使用OC 对象


- (oneway void)release {
}

不放在自动释放池(返回self重写了release方法)
- (instancetype)autorelease {
    return self;
}

增加引用计数 
- (instancetype)retain {
    return self;
}

单例引用计数永远是1
- (NSUInteger)retainCount {
    return 1;
}

3、抽取宏

//  Singleton.h
//  单例模式


// ## 拼接前后两个字符串
// .h文件用 Singleton_h
#define Singleton_h(name)   + (instancetype)shared##name

// .m文件用 Singleton_m
// \表示\后面的内容都是#define这个宏的内容
#if __has_feature(objc_arc) // arc环境
    #define Singleton_m(name) \
    + (instancetype)shared##name { \
    return [[self alloc] init]; \
    }\
    \
    + (instancetype)allocWithZone:(struct _NSZone *)zone {\
    static id instance;\
    static dispatch_once_t onceToken;\
    dispatch_once(&onceToken, ^{\
    instance = [super allocWithZone:zone];\
    });\
    return instance;\
    }\
    \
    - (id)copyWithZone:(nullable NSZone *)zone {\
    return self;\
    }
#else // 非arc环境
    #define Singleton_m(name) \
    + (instancetype)shared##name { \
    return [[self alloc] init]; \
    }\
    \
    + (instancetype)allocWithZone:(struct _NSZone *)zone {\
    static id instance;\
    static dispatch_once_t onceToken;\
    dispatch_once(&onceToken, ^{\
    instance = [super allocWithZone:zone];\
    });\
    return instance;\
    }\
    \
    - (id)copyWithZone:(nullable NSZone *)zone {\
    return self;\
    }\
    - (oneway void)release {}\
    \
    - (instancetype)autorelease {\
    return nil;\
    }\
    \
    - (instancetype)retain {\
    return self;\
    }\
    \
    - (NSUInteger)retainCount {\
    return 1;\
    }
#endif
上一篇 下一篇

猜你喜欢

热点阅读