美文网首页
Socket详解《二》---使用socket请求百度首页数据

Socket详解《二》---使用socket请求百度首页数据

作者: 冰棍儿好烫嘴 | 来源:发表于2019-02-28 14:11 被阅读0次

上一篇文章中介绍了使用socket和服务端进行通信的基本过程,本文使用socket实现开发中最基本的网络请求过程。属于最底层的网络请求,弄明白socket通信过程,对于网络理解会更加深刻

全部代码如下,上一篇文章中已经对基本方法做了详细的描述,本文着重描述如何使用socket实现网络请求。

#import "GetBaiDuSocketViewController.h"
#import <sys/socket.h>
#import <netinet/in.h>
#import <arpa/inet.h>


@interface GetBaiDuSocketViewController ()
@property (nonatomic,assign) int clientSocket;
@property (strong, nonatomic)  UIWebView *webView;

@end

@implementation GetBaiDuSocketViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self.view addSubview:self.webView];
    
   BOOL result = [self connectWithIp:@"61.135.169.121" Host:80];
    if (!result) {
        NSLog(@"连接失败");
        return;
    }
    NSLog(@"连接成功");
    
    //http请求头
    NSString * requestHeader = @"GET / HTTP/1.1\r\n"
                                "Host: www.baidu.com\r\n"
                                "Connection: close\r\n\r\n";

    //接收到的数据包含相应头和响应体
   NSString * response = [self sendAdnReceveMsgWithMsg:requestHeader];
    
    
    //http协议要求,请求结束后要关闭连接
    close(self.clientSocket);
    
    //取出相应体  相应头结束的标示:\r\n\r\n
    NSRange range = [response rangeOfString:@"\r\n\r\n"];
    response = [response substringFromIndex:range.location+range.length];

    [self.webView loadHTMLString:response baseURL:[NSURL URLWithString:@"http://www.baidu.com"]];
    
}

//建立连接
-(BOOL) connectWithIp:(NSString *)ip Host:(int)host{
    //1创建socket
    //第一个参数:domain 协议簇 制定IPv4或者IPv6
    //第二个参数:Type socket类型 流socket 数据报socket
    //第三个参数:协议类型 TCP/UDP
    int clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    self.clientSocket = clientSocket;
    //2连接服务器
    //第一个参数:socket的描述符
    //第二个参数:结构体 ip地址和端口
    //第三个参数:结构体长度 sizeof()
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(ip.UTF8String);
    //调整字节顺序,从大到小或者从小到大。要和后台和其他端一致
    addr.sin_port = htons(host);
    
    int result = connect(clientSocket, (const struct sockaddr *) &addr, sizeof(addr));
    
    if (result != 0) {
        NSLog(@"失败");
        return NO;
    }
    NSLog(@"连接成功");
    return YES;
}

//发送请求
-(NSString *)sendAdnReceveMsgWithMsg:(NSString *)msg{
    //3.发送数据
    /**
     参数:
     带一个参数:socket
     第二个参数:要发送的数据的指针
     第三个:数据的大小,字符数
     第四个:是否要阻塞线程,一般填0
     
     //返回值:成功则返回实际传送出去的字符数,失败返回-1,错误原因存于errno 中
     */
    const char * str = msg.UTF8String;
    ssize_t sendCount = send(self.clientSocket, str, strlen(str), 0);
    NSLog(@"发送的字节数 %zd",sendCount);
    
    //4.接受服务器返回的数据
    /**
     带一个参数:socket
     第二个参数:接受的字节数组
     第三个:数据的大小,字符数
     第四个:是否要阻塞线程,一般填0
     */
    
    NSMutableData * mData = [NSMutableData data];
    
    uint8_t buffer[1024];
    ssize_t recvCont = recv(self.clientSocket, buffer, sizeof(buffer), 0);

    [mData appendBytes:buffer length:recvCont];
    //服务器返回多次数据,做拼接将所有的数据拼接起来
    
    while (recvCont != 0) {
       recvCont = recv(self.clientSocket, buffer, sizeof(buffer), 0);
        [mData appendBytes:buffer length:recvCont];
        NSLog(@"接受到的字节数 %zd",recvCont);
    }
    
    NSLog(@"接受到的字节数 %zd",recvCont);
    //把字节数组转换成字符串
//    NSData * recvData = [NSData dataWithBytes:buffer length:recvCont];
    NSString * recvMsg = [[NSString alloc]initWithData:mData.copy encoding:NSUTF8StringEncoding];
        NSLog(@"收到的数据:%@",recvMsg);
    return recvMsg;
    
}

-(UIWebView *)webView {
    if(!_webView){
        _webView = [[UIWebView alloc]initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
    }
    return _webView;
}

@end

需要注意的点:

1、使用socket请求数据,不能使用域名,必须使用IP(一般的网络框架会多一步将域名解析成IP的步骤,这里没有,所以只能写真实IP),端口号一般默认80
使用终端ping 域名就可以拿到对应的真实IP,如:


获取IP

2、向服务器请求数据,就是和服务器建立连接之后,向服务器发送请求信息(www.baidu.com&参数)但是在使用socket做请求的时候,我们需要将对应的请求头信息一并传过去。AFN等第三方将请求头信息封装之后默认传入,这一步不需要操作。

 //http请求头
    NSString * requestHeader = @"GET / HTTP/1.1\r\n"
                                "Host: www.baidu.com\r\n"
                                "Connection: Keep-Alive\r\n\r\n";

获取请求头信息,可以使用浏览器的监控功能,使用Chrome打开www.baidu.com 之后使用command+option+i 打开监控页面,选择nectwork中的Header response Header 中的信息
其中GET / HTTP/1.1Host: www.baidu.com为必填项。在拼接各个字段的时候需要在每个字段后面加上\r\n最后一个字段加上两个\r\n。最后的两个\r\n\r\n之后会作为请求头结束标志使用

3、按上面的操作,就可以请求到对应的百度页面的信息,但是请求到的信息是包含响应头和相应体的,所以要在接收到的数据中用\r\n\r\n进行截取,拿到对应的响应体

 //取出相应体  相应头结束的标示:\r\n\r\n
    NSRange range = [response rangeOfString:@"\r\n\r\n"];
    response = [response substringFromIndex:range.location+range.length];

4、关于baseUrl:

[self.webView loadHTMLString:response baseURL:[NSURL URLWithString:@"http://www.baidu.com"]];

这里的baseUrl我们在一般情况下是写nil的,但是如果是一个网页数据,请求到的只是html数据,对应的图片资源和css等有时候是不会都返回,所以要协商baseUrl,表明这些资源的地址

5、记得在plist文件中设置https白名单字段,应为在请求http://www.baidu.com的时候会进行重定向,所以不设置的话会请求失败。

相关文章

网友评论

      本文标题:Socket详解《二》---使用socket请求百度首页数据

      本文链接:https://www.haomeiwen.com/subject/sqchuqtx.html