1.首先你需要用CocoaPods導入這個庫:
pod'CocoaAsyncSocket'
2.而后我們新建一個DCSocketManager類來管理這個類的一些代理方法,并生成一個本類的單例:
@interfaceDCSocketManager() {
NSString*_serverHost;//IP或者域名
int_serverPort;//端口,https一般是443
GCDAsyncSocket *_asyncSocket;//一個全局的對象
}
@property(nonatomic,strong)NSMutableData*sendData;//最終拼接好的需要發(fā)送出去的數(shù)據(jù)
@property(nonatomic,copy)NSString*uriString;//具體請求哪個接口,比如https://xxx.xxxxx.com/verificationCode里的verificationCode
@property(nonatomic,strong)NSDictionary*paramters;//Body里面需要傳遞的參數(shù)
@property(nonatomic,copy) CompletionHandler completeHandler;//收到返回數(shù)據(jù)后的回調(diào)Block
@property(nonatomic,strong)NSMutableArray*dcNetArr;//網(wǎng)絡請求參數(shù)的暫存數(shù)組,后面會用到
@end
3.用socket連接http接口的域名與端口:
[_asyncSocket connectToHost:_serverHost onPort:_serverPort error:nil];
4.組裝要發(fā)送的報文NSData:
- (NSMutableData*)sendData {
NSMutableData*packetData = [[NSMutableDataalloc] init];
NSData*crlfData = [@"\r\n"dataUsingEncoding:NSUTF8StringEncoding];//回車換行是http協(xié)議中每個字段的分隔符
[packetData appendData:[[NSStringstringWithFormat:@"GET /%@ HTTP/1.1",self.uriString] dataUsingEncoding:NSUTF8StringEncoding]];//拼接的請求行
[packetData appendData:crlfData];//每個字段后面都要跟一個回車換行
[packetData appendData:[@"DCVer: 1"dataUsingEncoding:NSUTF8StringEncoding]];//拼接的請求頭字段,這個鍵值對和服務器協(xié)商內(nèi)容,一般不止一個
[packetData appendData:crlfData];
?[packetData appendData:[@"DCAid: test"dataUsingEncoding:NSUTF8StringEncoding]];//拼接的請求頭字段,這個鍵值對和服務器協(xié)商內(nèi)容,一般不止一個
[packetData appendData:crlfData];?
?[packetData appendData:[@"Content-Type: application/json; charset=utf-8"dataUsingEncoding:NSUTF8StringEncoding]];//發(fā)送數(shù)據(jù)的格式
[packetData appendData:crlfData];
?[packetData appendData:[@"User-Agent: GCDAsyncSocket8.0"dataUsingEncoding:NSUTF8StringEncoding]];//代理類型,用來識別用戶的操作系統(tǒng)及版本等信息,這里我隨便填的,一般情況沒什么用
[packetData appendData:crlfData];?
?[packetData appendData:[@"Host: xxx.xxxxxx.com"dataUsingEncoding:NSUTF8StringEncoding]];//IP或者域名
[packetData appendData:crlfData];
NSError*error;
NSData*bodyData = [NSJSONSerializationdataWithJSONObject:self.paramters options:0error:&error];
NSString*bodyString = [[NSStringalloc] initWithData:bodyData encoding:NSUTF8StringEncoding];//生成請求體的內(nèi)容
[packetData appendData:[[NSStringstringWithFormat:@"Content-Length: %ld", bodyString.length] dataUsingEncoding:NSUTF8StringEncoding]];//說明請求體內(nèi)容的長度
[packetData appendData:crlfData];
?[packetData appendData:[@"Connection:close"dataUsingEncoding:NSUTF8StringEncoding]];
?[packetData appendData:crlfData];?
?[packetData appendData:crlfData];//注意這里請求頭拼接完成要加兩個回車換行//以上http頭信息就拼接完成,下面繼續(xù)拼接上body信息
NSString*encodeBodyStr = [NSStringstringWithFormat:@"%@\r\n\r\n", bodyString];//請求體最后也要加上兩個回車換行說明數(shù)據(jù)已經(jīng)發(fā)送完畢
[packetData appendData:[encodeBodyStr dataUsingEncoding:NSUTF8StringEncoding]];
returnpacketData;
}
5.若想支持https接口,則需要加下面一個方法:
- (void)doTLSConnect:(GCDAsyncSocket *)sock {//HTTPS
NSMutableDictionary*sslSettings = [[NSMutableDictionaryalloc] init];
NSData*pkcs12data = [[NSDataalloc] initWithContentsOfFile:[[NSBundlemainBundle] pathForResource:@"xxx.xxxxxxx.com"ofType:@"p12"]];//已經(jīng)支持https的網(wǎng)站會有CA證書,給服務器要一個導出的p12格式證書
CFDataRefinPKCS12Data = (CFDataRef)CFBridgingRetain(pkcs12data);
CFStringRefpassword =CFSTR("xxxxxx");//這里填寫上面p12文件的密碼
constvoid*keys[] = { kSecImportExportPassphrase };
constvoid*values[] = { password };
CFDictionaryRefoptions =CFDictionaryCreate(NULL, keys, values,1,NULL,NULL);
CFArrayRefitems =CFArrayCreate(NULL,0,0,NULL);
?OSStatus securityError = SecPKCS12Import(inPKCS12Data, options, &items);
CFRelease(options);
CFRelease(password);
if(securityError == errSecSuccess) {
NSLog(@"Success opening p12 certificate.");
?}
CFDictionaryRefidentityDict =CFArrayGetValueAtIndex(items,0);?
?SecIdentityRef myIdent = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity);?
?SecIdentityRef certArray[1] = { myIdent };
CFArrayRefmyCerts =CFArrayCreate(NULL, (void*)certArray,1,NULL);?
?[sslSettings setObject:(id)CFBridgingRelease(myCerts) forKey:(NSString*)kCFStreamSSLCertificates];?
?[sslSettings setObject:@"api.pandaworker.com"forKey:(NSString*)kCFStreamSSLPeerName]; [sock startTLS:sslSettings];//最后調(diào)用一下GCDAsyncSocket這個方法進行ssl設置就Ok了
}
6.至此用socket調(diào)用http接口的方法已經(jīng)寫完了,那么我們調(diào)用之后怎么獲取返回數(shù)據(jù)呢,請往下看:
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData*)data withTag:(long)tag
{//讀取到返回數(shù)據(jù)時會調(diào)用
NSLog(@"didReadData length: %lu, tag: %ld", (unsignedlong)data.length, tag);
if(nil!=self.completeHandler) {
//如果請求成功,讀取到服務器返回的data數(shù)據(jù)一般是一串字符串,需要根據(jù)返回數(shù)據(jù)格式做相應處理解析出來
NSString*string = [[NSStringalloc] initWithData:data encoding:NSUTF8StringEncoding];//
NSLog(@"%@", string);
NSRangestart = [string rangeOfString:@"{"];
NSRangeend = [string rangeOfString:@"}\r\n"];
NSString*sub;
if(end.location !=NSNotFound&& start.location !=NSNotFound) {
//如果返回的數(shù)據(jù)中不包含以上符號,會崩潰
sub = [string substringWithRange:NSMakeRange(start.location, end.location-start.location+1)];//這就是服務器返回的body體里的數(shù)據(jù)
NSData*subData = [sub dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary*subDic = [NSJSONSerializationJSONObjectWithData:subData options:0error:nil];
self.completeHandler(subDic);
?}?
?}
?[sock readDataWithTimeout:-1tag:0];
}