IOS开发之网络编程(URL、HTTP和Socket)

C/S和B/S

C/S:客户端/服务器 B/S:浏览器/服务器

URL的基本格式

协议://主机地址:端口号/路径
协议:不同的协议代表不同的资源获取方式
主机地址:主机的唯一标示(IP地址、域名)
路径:资源在主机中的具体位置

URL的常见协议:HTTP、FTP、mailto、File、tel://、sms://

HTTP协议

Hyper Text Transport Protocol (超文本传输协议)

  • 浏览器和Web服务器通讯时候遵守的约定
  • 互联网使用最多的协议
  • 提供超文本传输服务
  • 通过浏览器打开网站使用的就是HTP提供的服务,开发App也会经常使用HTTP协议从网络上获取数据
  • 底层要求是TCP协议

使用HTTP时的设置

方式一: 使用文本编辑Info.plist, 在当中添加:

<!--回到过去不安全的HTTP网络请求,能任意进行HTTP请求 (不建议这样做, 原因见下文)-->
<key>NSAppTransportSecurity</key>
<dict>
  <key>NSAllowsArbitraryLoads</key>
  <true/>
</dict>

发生异步请求(NSURLConnection)

被淘汰的方法 方便理解原理

NSURL *url = [NSURL URLWithString:@"https://www.baidu.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];

[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *_Nullable response,NSData *_Nullable data,NSError *_Nullable connectionError){
  if(!concentionError){
    NSString *html = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"%@",html);
  }else{
    NSLog(@"连接错误 %@",connectionError);
  }
  
}];
//queue:队列可以决定在子线程还是主线程上执行
//completionHandler 方法的属性
//response 服务器返回的相应头
//data 服务器返回的相应体
//connectionError 连接错误

ASCII

国标历程都兼容ASCII
GB2312 -> GBK -> GB18030 -> BIG5
Unicode -> UTF-8

IP地址

  • 两个计算机通讯必须要知道的:IP地址和端口号
  • IP地址:IP地址是一个32位的二进制数,通常被分割为8位二进制数,通常用点分10进制表示
  • 127.0.0.1 回环地址(本机地址) 255.255.255.255(广播)0.0.0.0(any)
  • 唯一标示互联网上的一台计算机(ip地址不好记忆,所以有了域名)
  • 一个计算机可能有多个可用的ip地址,比如:两块网卡(集成网卡和无线网卡)
  • 内网的计算机,都通过路由器上网。他们对外的地址都是路由器的ip地址

端口号

  • 标示进程(程序)的逻辑地址,不同进程(程序)的标示
  • 端口取值范围:0~65535

端口的分类 低中高三种端口

  • 公认端口(Well Known Ports):这类端口也常称之为"常用端口"。这类端口的端口号从0到1024,它们紧密绑定于一些特定的服务。通常这些端口的通信明确表明了某种服务的协议,这种端口是不可再重新定义它的作用对象。比如;http默认80,ftp默认21
  • 注册端口(Registered Ports):端口号从1025到49151。分配给用户进程或应用程序。这些进程主要是用户选择安装的些应用程序,而不是已经分配好了公认端口的常用程序
  • 动态和/私有端口(Dynamic and/or Private Ports):端口号从49152到65535。之所以称为动态端口,是因为它一般不固定分配某种服务而是动态分配

TCP/IP模型

  • 应用层:TCP/IP网络模型应用层对应OSI模型的前三层,为用户提供所需的各种服务,例如:FTP、Telnet、DNS、SMTP、HTTP
  • 传输层:为应用层提供端到端的通信功能,保证了数据包的传输顺序及数据完整性。两个主要协议TCP和UDP
  • 网络层:解决主机到主机的通信问题。它所保护的协议设计数据包在整个网络上的逻辑传输。注重重新赋予主机一个P地址来完成对主机的寻址,它还负责数据包在多种网络中的路由。该层有三个主要协议:网际协议(|P)、互联网组管理协议(IGMP)和互联网控制报文协议(ICMP)
  • 网络接入层:负责监视数据在主机和网络之间的交换

传输层:端口到端口
网络层:主机到主机
网络接入层:网卡层
在这里插入图片描述

传输层协议:TCP/UDP

  • TCP(传输控制协议)TCP协议提供的是一种可靠的、通过“三次握手”来连接的数据传输服务
  • UDP(用户数据报协议)UDP协议提供的则是不保证可靠性(并不是不可靠)、无连接的数据传输服务

Socket

两个计算机通讯的过程,就像两个人打电话一样

  • Socket又称“套接字”,应用程序通过“套接字”向网络发送请求或向网络做出应答
  • 网络通信其实就是Socket之间的通信
  • 数据在两个Socket之间通过IO传输数据
  • Socket是纯C语言的,是跨平台的
  • HTTP协议是基于Socket的,HTTP协议的底层使用的就是Socket,Socket在应用层和传输层之间

Socket的通信过程

  • 创建Socket
  • 连接到服务器
  • 发送数据给服务器
  • 从服务器接收数据
  • 关闭连接

Socket的创建

  • 导入头文件
#import<sys/socket.h>
#import<netinet/in.h>
#import<arpa/inet.h>
  • 创建Socket
int socket(int domain, int type, int protocol);
//参数1 domain 协议域 AF_INET--IPV4
//参数2 type   socket类型 S0CK_STREAM(TCP)/SOCKET_DGRAM(UDP)
//参数3 protocol IPPROTO_TCP/IPPROTO_UDP 如果传入0会根据第二个参数选择合适的值
//返回值 0创建成功 socket的描述符

int clientSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

Socket连接服务器

//2连接服务器
int connect(int sockfd,struct sockaddr* serv_addr,int addrlen);
//参数1 Socket 描述符
//参数2 指向数据结构sockaddr的指针,其中包括目的端口和IP地址
//参数3 参数2sockaddr的长度,可以通过sizeof(struct sockaddr)获得
//返回值 成功返回0,失败非0,错误码GetLastError()

struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");//IP地址
addr.sin_port = htons(12345);//端口号

int result = connect(clientSocket,(const struct sockaddr *)&addr,sizeof(addr));

模拟服务器

打开 Netcat,模拟服务器,打开终端:nc -lk 端口号
终端下用于调试和检查网络的工具:nc -> netcat

Socket收发数据

  • 发送数据给服务器
const char *sendMessage = "hello world";

ssize_t sendLen = send(clientSocket, sendMessage,strlen(sendMessage),0);
NSLog(@"发送的字节数:%ld", sendLen);

//参数1 指定发送端套接字描述符
//参数2 指明一个存放应用程式要发送数据的缓冲区
//参数3 指明实际要发送的数据的字节数
//参数4 一般置0
//返回值 成功则返回实际传送出去的字符数,失败返回-1,错误原因存于errno中
  • 接收服务器的数据
recv(int,void *,size_t,int)
//返回的是实际接收的字节个数

//收到容量为1024个字节Byte
unit8_t buffer[1024];
ssize_t recvCount = recv(clientSocket,buffer,sizeof(buffer),0);
NSLog(@"接收的字节数:%zd",recvCount);

NSData *data = [NSData dataWithBytes:buffer length:recvCount];
NSString *recvMsg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"接收的数据:%@",recvMsg);
//收到的字节多时,分批接收
unit8_t buffer[1024];
NSMutableData *mData = [NSMutableData data];
ssize_t recvCount = recv(clientSocket,buffer,sizeof(buffer),0);
[mData appendBytes:buffer length:recvCount];

while(recvCount!=0){
recvCount = recv(clientSocket,buffer,sizeof(buffer),0);
[mData appendBytes:buffer length:recvCount];
}

NSString *recvMsg = [[NSString alloc] initWithData:mdata.copy encoding:NSUTF8StringEncoding];

Socket关闭连接

close(clientSocket);

Socket请求百度

获取请求头:浏览器 -> 打开百度 -> 控制台 -> Network -> 第一个请求的Headers Request -> Headers的前三个属性

在这里插入图片描述

connect(){//Socket连接服务器,代码自己写};
sendAndRecv(){//Socket收发数据,代码自己写};

//连接百度的服务器
BOOL result = [self connect:@"61.135.169.125" port:80];

//最后加\r\n换行,最后一行2个
//构造http请求头(加user-agent属性就能识别设备)
NSString *request = @"GET / HTTP/1.1\r\n"  
                     "Host: www.baidu.com\r\n"
                     "Connection: close\r\n\r\n";
//服务器返回的相响应头和响应体(响应头是不要的)
NSString *respose = [self sendAndRecv:request];

//关闭连接
close(self.clientSocket);

//截取响应头 响应头结束表示\r\n\r\n
NSRange range = [respose rangeOfString:@"\r\n\r\n"];
NSString *html =[respose substringFromIndex:range.length+range.location];

//显示
//baseURL能去对应URL取需要的文件,图片之类
[self.webView loadHTMLString:html baseURL:[NSURL URLWithString:@"http://www.baidu.com"]]; 

请求头/短连接和长连接

NSString *request = @"GET / HTTP/1.1\r\n"  
                     "Host: www.baidu.com\r\n"
                     "Connection: close\r\n\r\n";
加user-agent属性就能识别设备
Connection:keep-alive 保持连接,过一会销毁,保证短时间内的数据请求不用再创造连接
Connection:close 关闭

http/1.0 短连接当响应结束后连接会立即断开
http/1.1 长连接当响应结東后,连接会等待非常短的时间,如果这个时间内没有新的请求,就断开连接

配置Apache

本地模拟web服务器

  • 在当前用户的目录创建一个文件夹
  • 打开finder进入/etc/apache2
  • 此目录是只读的,要想操作此目录先更改柷限,打开apache2文件夹的显示简介
  • 修改httped.conf前,先备份下该文件,修改此文件中的
DocumentRoot"/Users/你的用户名/myweb
<Directory"/Users/你的用户名/myweb">
添加上Indexes
Options Indexes FollowSymLinks Multiviews
MultiviewsMatch Any
把前面的#号去掉
#LoadModule php5_module libexec/apache2/libphp5.so
  • 启动Apache的命令:
    sudo apachectl-k restart 重启 Apache
    sudo apachecti-k start 启动 Apache
    sudo apachectl-k stop 停止 Apache

NSURLConnection获取网络数据

//第一种方式 获取网络数据 无法设置请求头 无法控制缓存 无法设置超时时长
NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/demo.json"];
NSData *data = [NSData dataWithContentsOfURL:url];
NSString *html = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@",html);

//第二种方式 获取网络数据 过时方法上面(发生异步请求(http)内容)
NSURL *url = [NSURL URLWithString:@"https://www.baidu.com"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//可以修改请求头  值 键,会帮你拼接好
[request setValue:@"" forHTTPHeaderField:@""];

[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *_Nullable response,NSData *_Nullable data,NSError *_Nullable connectionError){
    NSString *html = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"%@",html);
}];
//第二种方法控制缓存 设置超时时长(默认60秒)
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:15];

cachePolicy属性是枚举,多个选项,参考下面,默认0

在这里插入图片描述

错误处理

[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *_Nullable response,NSData *_Nullable data,NSError *_Nullable connectionError){
  if(!concentionError){
    //解析response,分析网页状态
    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
    //200(成功) 服务器已成功处理了请求。通常,这表示服务器提供了请求的网页
    //304(未修改) 自从上次请求后,请求的网页未被修改过。服务器返回此响应时,不会返回网页内容
    if(httpResponse.statusCode ==200||httpResponse.statusCode==304)      
    {NSString *html = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];NSLog(@"%@",html);}else{
    NSLog(@"服务器内部错误");
    }
  }else{
    NSLog(@"连接错误 %@",connectionError);
  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值