ios基础篇(十六)—— 网络之sockct

一、网络基本概念

  • 客户端:应用  C/S   B/S
  • 服务器:为客户端提供服务、数据、资源的机器
  • 请求:客户端向服务器索取数据
  • 响应:服务器对客户端的请求作出反应,一般是返回给客户端数据
  • 服务器
    • 内网服务器
    • 外网服务器
    • 本地测试服务器

二、URL

  • 准备获取网络上的资源,首先要了解URL
  • 什么是URL
    • Uniform Resource Locator(统一资源定位符)
    • 网络中每一个资源都对应唯一的地址—URL
  • URL的基本格式
    • 协议://主机地址:端口号/路径

协议: 不同的协议代表不同的资源获取方式

主机地址:主机的唯一标示(IP地址、域名)

路径:资源在主机中的具体位置

三、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地址

四、端口号

  • 端口号
    • 标示进程(程序)的逻辑地址,不同进程(程序)的标示
    • 端口取值范围: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。之所以称为动态端口,是因为它 一般不固定分配某种服务,而是动态分配

五、网络模型

  • 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,失败返回非0
    struct sockaddr_in serverAddr;
    //IPV4
    serverAddr.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) {
            //把二进制数据转换成NSString
            NSString *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 向服务器发送数据
    //成功则返回实际传送出去的字符数,失败返回-1
    const 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;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值