天天看點

iOS 使用Socket模拟手機通路百度

1. 連接配接百度伺服器

// 1. 連接配接百度的伺服器
    BOOL result = [self connectIp:@"220.181.111.188" port:80];
    if (!result) {
        NSLog(@"連接配接失敗");
        return;
    }
    NSLog(@"連接配接成功");


// 連接配接伺服器
- (BOOL)connectIp:(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. 構造請求頭

// 模拟構造Http請求頭
    NSString *request = @"GET / HTTP/1.1\r\n"
    "Host: www.baidu.com\r\n"
    "\r\n";
    
    NSLog(@"%@", request);
           

3. 通路伺服器,并擷取傳回内容

// 伺服器傳回的響應頭  響應體
    NSString *response = [self sendAndRecv:request];
    NSLog(@"傳回的資料: %@", response);


// 發送和接收資料
- (NSString *) sendAndRecv:(NSString *)sendMsg {
    const char *msg = sendMsg.UTF8String;
    ssize_t sendCount = send(self.clientSocket, msg, strlen(msg), 0);
    NSLog(@"發送的位元組數 %zd", sendCount);
    
    uint8_t buffer[1024];
    NSMutableData *datas = [NSMutableData data];
    ssize_t recvCount = recv(self.clientSocket, buffer, sizeof(buffer), 0);
    [datas appendBytes:buffer length:recvCount];
    
    while (recvCount != 0) {
        recvCount = recv(self.clientSocket, buffer, sizeof(buffer), 0);
        NSLog(@"接收的位元組數 %zd", recvCount);
        [datas appendBytes:buffer length:recvCount];
    }
    
    NSString *recvMsg = [[NSString alloc] initWithData:datas encoding:NSUTF8StringEncoding];
    return recvMsg;
}

           

4. 關閉連接配接,并将網頁顯示在UIWebView中

// 關閉連接配接
    close(self.clientSocket);
    
    // 截取響應頭,隻保留響應體, 響應頭結束的辨別 \r\n\r\n
    // 找指定字元串所在的範圍,從它之後的第一個位置開始截取字元串
    NSRange range = [response rangeOfString:@"\r\n\r\n"];
    // 截取響應體
    NSString *html = [response substringFromIndex:range.length + range.location];
    
    // baseURL為html依賴的外部檔案所在的位址
    [self.webView loadHTMLString:html baseURL:[NSURL URLWithString:@"http://www.baidu.com"]];
           

5. 完成第四步之後,傳回的網頁是PC版的

要想使得傳回的網頁是手機版的,需要在添加請求頭時添加"User-Agent"這個請求頭,将第2步的請求頭内容更改為

// 模拟構造Http請求頭
    NSString *request = @"GET / HTTP/1.1\r\n"
    "Host: www.baidu.com\r\n"
    "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)\r\n"
    "Connection: keep-alive\r\n"
    "\r\n";
    
    NSLog(@"%@", request);
           

6. 完成代碼

//
//  ViewController.m
//  請求百度
//
//  Created by mazaiting on 18/1/3.
//  Copyright © 2018年 mazaiting. All rights reserved.
//

#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 connectIp:@"220.181.111.188" 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/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)\r\n"
    "Connection: keep-alive\r\n"
    "\r\n";
    
    NSLog(@"%@", request);
    // 伺服器傳回的響應頭  響應體
    NSString *response = [self sendAndRecv:request];
    NSLog(@"傳回的資料: %@", response);
    
    // 關閉連接配接
    close(self.clientSocket);
    
    // 截取響應頭,隻保留響應體, 響應頭結束的辨別 \r\n\r\n
    // 找指定字元串所在的範圍,從它之後的第一個位置開始截取字元串
    NSRange range = [response rangeOfString:@"\r\n\r\n"];
    // 截取響應體
    NSString *html = [response substringFromIndex:range.length + range.location];
    
    // baseURL為html依賴的外部檔案所在的位址
    [self.webView loadHTMLString:html baseURL:[NSURL URLWithString:@"http://www.baidu.com"]];
}


// 連接配接伺服器
- (BOOL)connectIp:(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;
    }
}

// 發送和接收資料
- (NSString *) sendAndRecv:(NSString *)sendMsg {
    const char *msg = sendMsg.UTF8String;
    ssize_t sendCount = send(self.clientSocket, msg, strlen(msg), 0);
    NSLog(@"發送的位元組數 %zd", sendCount);
    
    uint8_t buffer[1024];
    NSMutableData *datas = [NSMutableData data];
    ssize_t recvCount = recv(self.clientSocket, buffer, sizeof(buffer), 0);
    [datas appendBytes:buffer length:recvCount];
    
    while (recvCount != 0) {
        recvCount = recv(self.clientSocket, buffer, sizeof(buffer), 0);
        NSLog(@"接收的位元組數 %zd", recvCount);
        [datas appendBytes:buffer length:recvCount];
    }
    
    NSString *recvMsg = [[NSString alloc] initWithData:datas encoding:NSUTF8StringEncoding];
    return recvMsg;
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (BOOL)prefersStatusBarHidden{
    return YES;
}

@end
           

繼續閱讀