AFNetWorking
NSString *baseUrl = @"https://api.500px.com/v1/photos";
NSDictionary *parameterDic = @{@"feature":@"popular",
@"exclude":@"Nude,People,Fashion",
@"sort":@"rating",
@"image_size":@"3",
@"include_store":@"store_download",
@"include_states":@"voted",
@"consumer_key":@"Fi13GVb8g53sGvHICzlram7QkKOlSDmAmp9s9aqC"
};
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager GET:baseUrl parameters:parameterDic progress:^(NSProgress * _Nonnull downloadProgress) {
NSLog(@"downloadProgress: %@", downloadProgress);
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(@"responseObject: %@", responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"error: %@", error);
}];
复制代码
AFHTTPSessionManager的初始化方法
- (instancetype)initWithBaseURL:(NSURL *)url
sessionConfiguration:(NSURLSessionConfiguration *)configuration
{
self = [super initWithSessionConfiguration:configuration];
if (!self) {
return nil;
}
// Ensure terminal slash for baseURL path, so that NSURL +URLWithString:relativeToURL: works as expected
if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
url = [url URLByAppendingPathComponent:@""];
}
self.baseURL = url;
self.requestSerializer = [AFHTTPRequestSerializer serializer];
self.responseSerializer = [AFJSONResponseSerializer serializer];
return self;
}
复制代码
在初始化AFHTTPSessionManager的时候,赋值了NSURLSessionConfiguration、AFHTTPRequestSerializer、AFJSONResponseSerizlizer。
NSURLSessionConfiguration的初始化
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
self = [super init];
if (!self) {
return nil;
}
if (!configuration) {
configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
}
self.sessionConfiguration = configuration;
self.operationQueue = [[NSOperationQueue alloc] init];
self.operationQueue.maxConcurrentOperationCount = 1;
self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];
self.responseSerializer = [AFJSONResponseSerializer serializer];
self.securityPolicy = [AFSecurityPolicy defaultPolicy];
#if !TARGET_OS_WATCH
self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
#endif
self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];
self.lock = [[NSLock alloc] init];
self.lock.name = AFURLSessionManagerLockName;
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
for (NSURLSessionDataTask *task in dataTasks) {
[self addDelegateForDataTask:task uploadProgress:nil downloadProgress:nil completionHandler:nil];
}
for (NSURLSessionUploadTask *uploadTask in uploadTasks) {
[self addDelegateForUploadTask:uploadTask progress:nil completionHandler:nil];
}
for (NSURLSessionDownloadTask *downloadTask in downloadTasks) {
[self addDelegateForDownloadTask:downloadTask progress:nil destination:nil completionHandler:nil];
}
}];
return self;
}
复制代码
SDWebImage
[_imgView sd_setImageWithURL:[NSURL URLWithString:entityModel.templateCover] completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
UIGraphicsBeginImageContextWithOptions(image.size, NO, 0);
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, image.size.width, image.size.height) cornerRadius:12];
[path addClip];
[image drawAtPoint:CGPointZero];
UIImage *clipImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
dispatch_async(dispatch_get_main_queue(), ^{
__strong typeof(weakSelf) strongSelf = weakSelf;
strongSelf.imgView.image = clipImage;
});
}];
复制代码
SDWebImage以类别为主,添加图片请求的方法,使用起来很方便。
我们通过UIImageView、UIButton的类别请求图片,类别中的方法会初始化SDWebImageDownloader和SDWebImageDownloaderOperation进行网络请求。同时,会设置NSOperation,进行任务的取消。SDWebImage添加了缓存机制,图片在下载完成后会议URL作为key存储到Memory和磁盘中。
个人在使用中觉得,框架提供了接口允许我们对下载后的图片进行处理,但是却没有与框架的缓存机制很好的结合,对图片做处理后没有进行缓存方面的替换。另外,缓存策略的实现也不是很好。
Socket
提起计算机网络,大家都会想起七层模型、五层模型或者是TCP/IP模型。本文以五层模型为基础。
- 应用层 (SMTP,HTTP,HTTPS等)
- 运输层 (TCP/UDP)
- 网络层 (IP)
- 数据链路层
- 物理层
七层模型将应用层细分为:应用层、表示层、会话层。TCP/IP模型将数据链路层和物理层合并为链路层。
传输层 (TCP/UDP)
上图描述了网络通信的流程。
UDP (用户数据报协议,User Datagram Protocol)
用户数据报协议UDP只是在IP的数据报服务之上增加了复用和分用功能以及差错检测。UDP的主要特点:
- 无连接,发送数据之前不需要建立连接(发送数据结束后也没有连接可释放),减少了开销和发送数据时的时延。
- 尽最大努力交付,不保证可靠交付。
- 面向报文,发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付给IP层。
- UDP没有拥塞控制
- UDP支持一对一、一对多、多对一、多对多的交互通信
- UDP首部开销小,只有8个字节,比TCP的20个字节要短。
TCP (传输控制协议,Transmission Control Protocol)
TCP协议的特点:
- 面向连接的运输层协议。
- 连接是点对点
- 提供可靠交付
- 提供全双工通信
- 面向字节流
首部字段的意义:
- 源端口、目的端口,各占2个字节,写入源端口号和目的端口号。
- 序号,占4个字节,TCP连接中传送的字节流中的每一个字节都是按顺序编号的,序号字段值指的是本报文段所发送的第一个字节的序号。
- 确认号,占4个字节,期望收到对方下一个报文段的第一个字节的序号。
- 数据偏移,占4位,指的是报文段数据起始处距离报文段起始处的距离。
- 保留,占6位
- 紧急(URG),当URG = 1时,表明本报文段有紧急数据,应尽快传送。
- 确认(ACK),仅当ACK = 1时确认号字段才有效。
- 推送PSH,当两个应用进程进行交互式通信时,一段的应用程序希望在键入一个命令后立即接收到对方的响应。
- 复位RST,当RST = 1时,表明TCP连接出现了严重差错,必须释放连接。
- 同步SYN,在连接建立时用来同步序号。
- 终止FIN,释放连接。
- 窗口,占2个字节。指的是发送本报文段的一方的接收窗口,窗口值告诉对方:从本报文段首部中的确认号算起,接收方目前允许对方发送的数据。
- 检验和,占2个字节。
- 紧急指针,占2个字节,仅当URG = 1时有意义,指出紧急数据的字节数。
- 选项,长度可变,最长可达40个字节
网络层 (IP)
网络层向上只提供简单灵活、无连接的、尽最大努力交付的数据包服务。
- 地址解析协议 ARP (Address Resolution Protocol)
- 逆地址解析协议 RARP (Reverse Address Resolution Protocol)
- 网际控制报文协议 ICMP (Internet Control Message Protocol)
- 网际组管理协议 IGMP (Internet Group Management Protocol)
套接字 (socket)
TCP连接的端点叫做套接字(socket)。
套接字 socket = (IP地址:端口号)
每一条TCP连接唯一地被通信两端的两个端点所确定。
TCP连接 = {socket1, socket2} = {(IP1 : port1), {IP2, socket2}}
例子:
echo客户端
#include <stdio.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <string.h>
int main {
// echo服务器的主机地址和端口号
char *echo_host = "192.168.1.20";
int echo_port = 7;
int sockfd;
struct sockaddr_in *server = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
// 设置将要连接的服务器的地址
server->sin_family = AF_INT;
server->sin_port = htons(echo_port); // 网络字节序
server->sin_addr.s_addr = inet_addr(echo_host);
// 创建套接字 (因特网地址族,套接字,默认协议)
sockfd = socket(AF_INET, SOCK_STREAM, 0);
// 连接到服务器
printf("Connecting to %s\n", echo_host);
printf("Numeric: %u\n", server->sin_addr);
connect(sockfd, (struct sockaddr *)server, sizeof(*server));
// 发送消息
char *msg = "Hello world";
printf("\nSend: '\%s'\n", msg);
write(sockfd, msg, strlen(msg));
// 接收返回结果
char *buffer = (char *)malloc(1000);
int bytes = read(sockfd, (void *)buffer, 1000);
printf("\nBytes received: &u\n", bytes);
printf("Text: %s\n", buffer);
// 结束通信
close(sockfd);
}
复制代码
echo服务器端
#include <stdin.h>
#include <netinet.h>
#include <sys/types.h>
#include <string.h>
int main {
char *echo_host = "192.168.1.20";
int echo_port = 7777;
int sockfd;
struct sockaddr_in *server = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
// 设置自身地址
server->sin_family = AF_INET;
server->sin_port = htons(echo_port);
server->sin_addr.s_addr = inet_addr(echo_host);
// 创建套接字
sockfd = socket(AF_INET, SOCK_STREAN, 0);
// 绑定地址
if (bind(sockfd, (struct sockaddr *)server, sizeof(*server))) {
printf("bind failed\n");
}
// 启用套接字
listen(sockfd, SOMAXCONN);
// 等待客户端发送数据的请求
int clientfd;
struct sockadd_in *client = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
int client_size = sizeof(*client);
char *buffer = (char *)malloc(1000);
int bytes;
printf("Wait for connection to port %u\n", echo_port);
// 接受连接请求
clientfd = accept(sokfd, (struct sockaddr *)client, &client_size);
while (1) {
// 接收数据
bytes = read(clientfd, (void *)buf, 1000);
if (bytes <= 0) {
close(clientfd);
printf("Connection closed");
exit(0);
}
printf("Bytes received: %u\n", bytes);
// 发送响应数据
write(clientfd, buf, bytes);
}
}
复制代码