Objective-C使用tcp socket发送http请求

       WWDC 15 提出的 ATS (App Transport Security) 是 Apple 在推进网络通讯安全的一个重要方式。在 iOS 9 和 OS X 10.11 中,默认情况下非 HTTPS 的网络访问是被禁止的,但可以在 Info.plist 中添加 NSAppTransportSecurity 字典并且将NSAllowsArbitraryLoads 设置为 YES 来禁用 ATS。

       不过,WWDC 16 中,Apple 表示将继续在 iOS 10 和 macOS 10.12 里收紧对普通 HTTP 的访问限制。从 2017 年 1 月 1 日起,所有的新提交 app 默认是不允许使用 NSAllowsArbitraryLoads 来绕过 ATS  限制的,也就是说,我们最好保证 app 的所有网络请求都是 HTTPS  加密的,否则可能会在应用审核时遇到麻烦。

       虽然12月21号苹果宣布推迟强制ATS ,具体截止时间未定,但我们还是要做好准备来应对苹果的强制政策,那有些时候,其实我们的业务还是不想由HTTP 改为HTTPS ,有没有什么更好的办法来绕过ATS呢?这个方案就是使用TCP Socket 来实现HTTP 协议,直接绕过ATS 的限制。

以下以使用GCDAsyncSocket框架实现TCP Socket为例,

#import "GCDAsyncSocket.h"

@interface GSDKHttpRequest() 

/**
 * 待发送的json串
*/
@property (strong, readwrite, nonatomic) NSString* json;
/**
 * http请求的域名
*/
@property (strong, readwrite, nonatomic) NSString* domain;
/**
 * http请求的端口,如服务端未指定,一般http使用80端口,https使用443端口
*/
@property (strong, readwrite, nonatomic) NSString* port;
/**
 * http请求的url中域名及端口之后的后缀
*/
@property (strong, readwrite, nonatomic) NSString* suffix;
/**
 * tcp套接字
*/
@property (strong, readwrite, nonatomic) GCDAsyncSocket* socket;

@end

1. 建立TCP Socket套接字:

self.domain = ip;
self.port = port;
self.suffix = urlSuffix;
self.json = jsonString;
self.socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:operation_processing_queue()];

 operation_processing_queue()为自定义queue,定义如下:

static dispatch_queue_t operation_processing_queue() {
    static dispatch_queue_t operation_processing_queue;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        operation_processing_queue = dispatch_queue_create("com.tencent.tcpTest", DISPATCH_QUEUE_SERIAL);
    });
    
    return operation_processing_queue;
}

 2. connect连接服务端:

NSError *error = nil;
if (![self.socket connectToHost:self.domain onPort:[self.port intValue] withTimeout:10.0 error:&error]) {
    NSLog(@"[Error]Error connecting: %@", error);
}

3. send发送数据:

/**
* 以下send内容根据具体协议内容填写,此仅为示例
*/
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
    NSLog(@"didConnectToHost, host:%@, port:%d", host, port);
    NSString* sendData = [NSString stringWithFormat:@"POST %@ HTTP/1.1\r\n", self.suffix];
    sendData = [sendData stringByAppendingString:[NSString stringWithFormat:@"Host: %@:%@\r\n", self.domain, self.port]];
    sendData = [sendData stringByAppendingString:@"Content-Type: application/json; charset=UTF-8\r\n"];
    sendData = [sendData stringByAppendingString:@"Connection: keep-alive\r\n"];
    sendData = [sendData stringByAppendingString:@"Accept: */*\r\n"];
    sendData = [sendData stringByAppendingString:@"User-Agent: QOSDemo/1 CFNetwork/808.2.16 Darwin/16.3.0\r\n"];
    sendData = [sendData stringByAppendingString:@"Accept-Language: zh-cn\r\n"];
    sendData = [sendData stringByAppendingString:@"Accept-Encoding: gzip, deflate\r\n"];
    sendData = [sendData stringByAppendingString:[NSString stringWithFormat:@"Content-Length: %lu\r\n", [self.json length]]];
    sendData = [sendData stringByAppendingString:@"\r\n"];
    sendData = [sendData stringByAppendingString:self.json];
    NSData* data = [sendData dataUsingEncoding:NSUTF8StringEncoding];
    // write data, timeout 3s
    [self.socket writeData:data withTimeout:3 tag:0];
}

 4. recv接收数据:

- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
    NSLog(@"socket:%p didWriteDataWithTag:%ld", sock, tag);
    [self.socket readDataWithTimeout:3 tag:0];
}

- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
    NSLog(@"socket:%p didReadData:withTag:%ld", sock, tag);
    NSString* string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"检查一下接收到的数据:%@", string);
    //和服务端协商下发数据格式,如本示例中“\r\n\r\n”之后的数据为所需要的json串
    NSArray *array = [string componentsSeparatedByString:@"\r\n\r\n"];
    if (array && [array count] == 2) {
        NSData* tmp = [array[1] dataUsingEncoding:NSUTF8StringEncoding];
        NSDictionary* result = [NSJSONSerialization JSONObjectWithData:tmp options:0 error:nil];
        NSLog(@"所需要的json串:%@", result);
        [self.socket disconnect];
    }
}

你可能感兴趣的:(iOS)