网络通信(应用)

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协议的特点:

  • 面向连接的运输层协议。
  • 连接是点对点
  • 提供可靠交付
  • 提供全双工通信
  • 面向字节流

首部字段的意义:

  1. 源端口、目的端口,各占2个字节,写入源端口号和目的端口号。
  2. 序号,占4个字节,TCP连接中传送的字节流中的每一个字节都是按顺序编号的,序号字段值指的是本报文段所发送的第一个字节的序号。
  3. 确认号,占4个字节,期望收到对方下一个报文段的第一个字节的序号。
  4. 数据偏移,占4位,指的是报文段数据起始处距离报文段起始处的距离。
  5. 保留,占6位
  6. 紧急(URG),当URG = 1时,表明本报文段有紧急数据,应尽快传送。
  7. 确认(ACK),仅当ACK = 1时确认号字段才有效。
  8. 推送PSH,当两个应用进程进行交互式通信时,一段的应用程序希望在键入一个命令后立即接收到对方的响应。
  9. 复位RST,当RST = 1时,表明TCP连接出现了严重差错,必须释放连接。
  10. 同步SYN,在连接建立时用来同步序号。
  11. 终止FIN,释放连接。
  12. 窗口,占2个字节。指的是发送本报文段的一方的接收窗口,窗口值告诉对方:从本报文段首部中的确认号算起,接收方目前允许对方发送的数据。
  13. 检验和,占2个字节。
  14. 紧急指针,占2个字节,仅当URG = 1时有意义,指出紧急数据的字节数。
  15. 选项,长度可变,最长可达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);
    }
}
复制代码

转载于:https://juejin.im/post/5af6465af265da0b7d0b7233

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值