一、网络基本概念
- 客户端:应用 C/S B/S
- 服务器:为客户端提供服务、数据、资源的机器
- 请求:客户端向服务器索取数据
- 响应:服务器对客户端的请求作出反应,一般是返回给客户端数据
- 服务器
- 内网服务器
- 外网服务器
- 本地测试服务器
二、URL
- 准备获取网络上的资源,首先要了解URL
- 什么是URL
- Uniform Resource Locator(统一资源定位符)
- 网络中每一个资源都对应唯一的地址—URL
- URL的基本格式
- 协议://主机地址:端口号/路径
协议: 不同的协议代表不同的资源获取方式
主机地址:主机的唯一标示(IP地址、域名)
路径:资源在主机中的具体位置
-
- 举例:
- http://www.itheima.com/
- http://www.itheima.com/images/xx00.png
- ftp://www.itheima.com/movies/cls.avi
- 举例:
- URL的常见协议
- HTTP、FTP、mailto、File、tel://、sms://
三、HTTP协议简介
- 什么是协议
- 双方规定好的约定
- 什么是HTTP协议
- HyperText Transport Protocol(超文本传输协议)
- 浏览器和Web服务器通讯时候遵守的约定
- 互联网使用最多的协议
- 提供超文本传输服务
- 通过浏览器打开网站使用的就是HTTP提供的服务,开发App也会经常使用HTTP协议从网络上获取数据
- 通过浏览器打开网站使用的就是http提供的服务
- 开发app,也会经常使用http协议从网络上获取数据
- 请求-响应
HTTP请求演示
- 演示请求百度首页
- 代码
//1 创建请求的地址NSURL *url = [NSURL URLWithString:@"http://www.baidu.com"];//2 创建请求对象,告诉服务器一些信息NSURLRequest *request = [NSURLRequest requestWithURL:url];//3 建立网络连接,向服务器发送请求,并接收服务器返回的响应[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {//网络请求完成后执行的方法//NSURLResponse *response, 服务器返回的响应对象//NSData *data, 服务器返回的二进制数据//NSError *connectionError 如果错误,返回的错误信息
// NSLog(@"%@",data);
// [data writeToFile:@"/Users/你的用户名/Desktop/123.html" atomically:YES];//把二进制数据 转换成字符串NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];NSLog(@"%@",str);}];
- Xcode7中的ATS
- ATS(App Transport Security) 默认禁止发送HTTP请求
<key>NSAppTransportSecurity</key>
<dict><key>NSAllowsArbitraryLoads</key><true/>
</dict>
三、IP地址
- 两个计算机通讯必须要知道的
- IP地址和端口号
- IP地址
- IP地址是一个32位的二进制数,通常被分割为8位二进制数,通常用点分10进制表示
- 192.168.1.1
- 127.0.0.1 回环地址(本机地址) 255.255.255.255 广播 0.0.0.0 any
- 唯一标示互联网上的一台计算机(ip地址不好记忆,所以有了域名)
- 一个计算机可能有多个可用的ip地址,比如:两块网卡(集成网卡和无线网卡)
- 内网的计算机,都通过路由器上网。他们对外的地址都是路由器的ip地址
- IP地址是一个32位的二进制数,通常被分割为8位二进制数,通常用点分10进制表示
四、端口号
- 端口号
- 标示进程(程序)的逻辑地址,不同进程(程序)的标示
- 端口取值范围:0~65535
- 端口的分类
- 公认端口(Well Known Ports)
- 这类端口也常称之为”常用端口"。这类端口的端口号从0到1024,它们紧密绑定于一些特定的服务。通常这些端口的通信明确表明了某种服务的协议,这种端口是不可再重新定义它的作用对象。比如:http默认80,ftp默认21 pop3 110 smtp 25
- 注册端口(Registered Ports)
- 端口号从1025到49151。分配给用户进程或应用程序。这些进程主要是用户选择安装的一些应用程序,而不是已经分配好了公认端口的常用程序。
- 动态和/或私有端口(Dynamic and/or Private Ports)
- 端口号从49152到65535。之所以称为动态端口,是因为它 一般不固定分配某种服务,而是动态分配
- 公认端口(Well Known Ports)
五、网络模型
- OSI七层网络模型
- 应用层
- 表示层
- 会话层
- 传输层
- 网络层
- 数据链路层
- 物理层
六、TCP/IP网络模型
- 应用层
- 对应OSI模型的前三层,为用户提供所需的各种服务,例如:FTP、Telnet、DNS、SMTP、HTTP等
- 传输层
- 为应用层提供端到端的通信功能,保证了数据包的传输顺序及数据完整性。两个主要协议:TCP和UDP
- 网络层
- 解决主机到主机的通信问题。它所保护的协议设计数据包在整个网络上的逻辑传输。注重重新赋予主机一个IP地址来完成对主机的寻址,它还负责数据包在多种网络中的路由。该层有三个主要协议:网际协议(IP)、互联网组管理协议(IGMP)和互联网控制报文协议(ICMP)。
- 网络接入层
- 负责监视数据在主机和网络之间的交换
TCP/UDP报文
IP报文
七、传输协议
- TCP(传输控制协议)
- TCP协议提供的是一种可靠的、通过“三次握手”来连接的数据传输服务
- UDP(用户数据报协议)
- UDP协议提供的则是不保证可靠性(并不是不可靠)、无连接的数据传输服务
八、Socket
- 两个计算机通讯的过程,就像两个人打电话一样
- Socket
- Socket又称“套接字”,应用程序通过“套接字”向网络发送请求或向网络做出应答
- 网络通信其实就是Socket之间的通信
- 数据在两个Socket之间通过IO传输数据
- Socket是纯C语言的,是跨平台的
- HTTP协议是基于Socket的,HTTP协议的底层使用的就是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类型 SOCK_STREAM(TCP)/SOCKET_DGRAM(UDP)//参数3 protocol IPPROTO_TCP/IPPROTO_UDP 如果 传入0 会根据第二个参数选择合适的 //返回值 >0 创建成功 socket的描述符示例:int clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
连接服务器
打开Netcat,模拟服务器
打开终端
nc -lk 12345
nc-->Netcat 终端下用于调试和检查网络的工具
连接服务器
int connect (int sockfd,struct sockaddr * serv_addr,int addrlen);
//参数1 sockfd 客户端socket//参数2 serv_addr 服务器地址结构体指针//参数3 addrlen 结构体数据长度//返回值 成功则返回0,失败返回非0示例:
//返回值 成功则返回0,失败返回非0struct sockaddr_in serverAddr;//IPV4serverAddr.sin_family = AF_INET;//端口serverAddr.sin_port = htons(12345);//ip地址serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");int connResult = connect(clientSocket, (const struct sockaddr *)&serverAddr, sizeof(serverAddr));if (connResult == 0) {NSLog(@"连接成功");}else{NSLog(@"连接失败");}
Socket收发数据
发送数据给服务器
const char *sendMessage = "hello world";ssize_t sendLen = send(clientSocket, sendMessage, strlen(sendMessage), 0);NSLog(@"发送的字节数:%ld",sendLen);
接收服务器返回的数据
uint8_t buffer[1024];
ssize_t recvLen = recv(clientSocket, buffer, sizeof(buffer), 0);if (recvLen > 0) {NSLog(@"接收了%ld个字节",recvLen);//从缓冲区读取数据NSData *data = [NSData dataWithBytes:buffer length:recvLen];NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];NSLog(@"%@",msg);}
关闭连接close(clientSocket);
请求百度
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIWebView *webView;
@end@implementation ViewController
- (void)viewDidLoad {[super viewDidLoad]; //发送请求NSURL *url = [NSURL URLWithString:@"https://m.baidu.com"];//请求NSURLRequest *request = [NSURLRequest requestWithURL:url];//发送异步请求[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {//response 服务器返回的响应头//data 服务器返回的响应体//connectionError 连接错误//判断请求是否有错误if (!connectionError) {//把二进制数据转换成NSStringNSString *html = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];NSLog(@"%@",html); //webView加载html[self.webView loadHTMLString:html baseURL:nil];}else{NSLog(@"连接错误 %@",connectionError);}}];
}
socket 请求百度
#import "ViewController.h"
#import <sys/socket.h>
#import <netinet/in.h>
#import <arpa/inet.h>
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIWebView *webView;
@property (nonatomic, assign) int clientSocket;
@end@implementation ViewController
- (void)viewDidLoad {[super viewDidLoad];//1 连接百度的服务器BOOL result = [self connect:@"61.135.169.125" port:80];if (!result) {NSLog(@"连接失败");return;}NSLog(@"连接成功");//构造http请求头NSString *request = @"GET / HTTP/1.1\r\n""Host: www.baidu.com\r\n""User-Agent: Mozilla/5.0 (Linux; Android 4.0.3; HTC One X Build/IML74K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19\r\n""Connection: keep-alive\r\n\r\n"; //http/1.0 短连接 当响应结束后连接会立即断开//http/1.1 长连接 当响应结束后,连接会等待非常短的时间,如果这个时间内没有新的请求,就断开连接//服务器返回的响应头 和 响应体NSString *respose = [self sendAndRecv:request];NSLog(@"----%@",respose);//关闭连接 http协议要求,请求结束后要关闭连接close(self.clientSocket); //截取响应头 响应头结束的表示\r\n\r\n<! //找到\r\n\r\n 的范围NSRange range = [respose rangeOfString:@"\r\n\r\n"];//从\r\n\r\n之后的第一个位置开始截取字符串 响应体NSString *html = [respose substringFromIndex:range.length + range.location ];[self.webView loadHTMLString:html baseURL:[NSURL URLWithString:@"http://www.baidu.com"]];}
//1 连接服务器
- (BOOL)connect:(NSString *)ip port:(int)port{int clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);self.clientSocket = clientSocket;struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_addr.s_addr = inet_addr(ip.UTF8String);addr.sin_port = htons(port);int result = connect(clientSocket, (const struct sockaddr *) &addr, sizeof(addr));if (result == 0) {return YES;}else{return NO;}
}
//2 发送和接收数据
- (NSString *)sendAndRecv:(NSString *)sendMsg {//3 向服务器发送数据//成功则返回实际传送出去的字符数,失败返回-1const char *msg = sendMsg.UTF8String;ssize_t sendCount = send(self.clientSocket, msg, strlen(msg), 0);NSLog(@"发送的字节数 %zd",sendCount); //4 接收服务器返回的数据//返回的是实际接收的字节个数uint8_t buffer[1024]; NSMutableData *mData = [NSMutableData data];ssize_t recvCount = recv(self.clientSocket, buffer, sizeof(buffer), 0);;[mData appendBytes:buffer length:recvCount]; //服务器会返回多次数据,等所有的数据都接收完成,再转换成字符串while (recvCount != 0) {recvCount = recv(self.clientSocket, buffer, sizeof(buffer), 0);NSLog(@"接收的字节数 %zd",recvCount);[mData appendBytes:buffer length:recvCount];} //把字节数组转换成字符串NSString *recvMsg = [[NSString alloc] initWithData:mData.copy encoding:NSUTF8StringEncoding];return recvMsg;
}