ios网络编程Word文档下载推荐.docx
《ios网络编程Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《ios网络编程Word文档下载推荐.docx(24页珍藏版)》请在冰豆网上搜索。
(id)sender;
-(IBAction)receiveData:
@end
定义属性inputStream和outputStream,它们输入流NSInputStream和输出流NSOutputStream类。
它们与服务器CFStream实现中的输入流CFReadStreamRef和输出流CFWriteStreamRef对应的。
视图控制器ViewController.m的初始化网络方法initNetworkCommunication代码:
-(void)initNetworkCommunication
CFReadStreamRefreadStream;
CFWriteStreamRefwriteStream;
CFStreamCreatePairWithSocketToHost(NULL,
(CFStringRef)@”192.168.1.103″,PORT,&
readStream,&
writeStream);
①
_inputStream=(__bridge_transferNSInputStream*)readStream;
②
_outputStream=(__bridge_transferNSOutputStream*)writeStream;
③
[_inputStreamsetDelegate:
self];
④
[_outputStreamsetDelegate:
⑤
[_inputStreamscheduleInRunLoop:
[NSRunLoopcurrentRunLoop]
forMode:
NSDefaultRunLoopMode];
⑥
[_outputStreamscheduleInRunLoop:
⑦
[_inputStreamopen];
⑧
[_outputStreamopen];
⑨
点击发送和接收按钮触发的方法如下:
/*点击发送按钮*/
(id)sender{
flag=0;
[selfinitNetworkCommunication];
/*点击接收按钮*/
flag=1;
它们都调用initNetworkCommunication方法,并设置操作标识flag,如果flag为0发送数据,flag为1接收数据。
流的状态的变化触发很多事件,并回调NSStreamDelegate协议中定义的方法stream:
handleEvent:
,其代码如下:
-(void)stream:
(NSStream*)theStreamhandleEvent:
(NSStreamEvent)streamEvent{
NSString*event;
switch(streamEvent){
caseNSStreamEventNone:
event=@”NSStreamEventNone”;
break;
caseNSStreamEventOpenCompleted:
event=@”NSStreamEventOpenCompleted”;
caseNSStreamEventHasBytesAvailable:
event=@”NSStreamEventHasBytesAvailable”;
if(flag==1&
&
theStream==_inputStream){
NSMutableData*input=[[NSMutableDataalloc]init];
uint8_tbuffer[1024];
intlen;
while([_inputStreamhasBytesAvailable])②
len=[_inputStreamread:
buffermaxLength:
sizeof(buffer)];
if(len>
0)
[inputappendBytes:
bufferlength:
len];
NSString*resultstring=[[NSStringalloc]
initWithData:
inputencoding:
NSUTF8StringEncoding];
NSLog(@”接收:
%@”,resultstring);
_message.text=resultstring;
caseNSStreamEventHasSpaceAvailable:
event=@”NSStreamEventHasSpaceAvailable”;
if(flag==0&
theStream==_outputStream){
//输出
UInt8buff[]=”HelloServer!
”;
[_outputStreamwrite:
buffmaxLength:
strlen((constchar*)buff)+1];
//关闭输出流
[_outputStreamclose];
caseNSStreamEventErrorOccurred:
event=@”NSStreamEventErrorOccurred”;
[selfclose];
caseNSStreamEventEndEncountered:
event=@”NSStreamEventEndEncountered”;
NSLog(@”Error:
%d:
%@”,[[theStreamstreamError]code],
[[theStreamstreamError]localizedDescription]);
default:
event=@”Unknown”;
NSLog(@”event——%@”,event);
在读取数据分支(NSStreamEventHasBytesAvailable)中,代码第①行为读取数据准备缓冲区,本例中设置的是1024个字节,这个大小会对流的读取有很多的影响。
第②行代码使用hasBytesAvailable方法判断是否流有数据可以读,如果有可读数据就进行循环读取。
第③行代码使用流的read:
maxLength:
方法读取数据到缓冲区,第1个参数是缓冲区对象buffer,第2个参数是读取的缓冲区的字节长度。
在写入数据分支(NSStreamEventHasSpaceAvailable)中,代码第④行是要写入的数据,第⑤行代码[_outputStream
write:
buff
strlen((const
char*)buff)+1]是写如数据方法。
第⑥和第⑦行代码[self
close]调用close方法关闭,close方法代码如下:
-(void)close
[_outputStreamremoveFromRunLoop:
nil];
[_inputStreamclose];
[_inputStreamremoveFromRunLoop:
[深入浅出Cocoa]iOS网络编程之CFNetwork
[深入浅出Cocoa]iOS网络编程之CFNetwork
罗朝辉(
本文遵循“署名-非商业用途-保持一致”创作公用协议
一,CFNetwork简介
首先来回顾下。
在前文《[深入浅出Cocoa]iOS网络编程之Socket》中,提到iOS网络编程层次模型分为三层:
∙Cocoa层:
NSURL,Bonjour,GameKit,WebKit
∙CoreFoundation层:
基于C的
CFNetwork和CFNetServices
∙OS层:
基于C的BSDsocket
前文讲的是最底层的socket,本文将介绍位于CoreFoundation中的CFNetwork。
CFNetwork只是对BSDsocket的进行了轻量级的封装,但在iOS中使用CFNetwork有一个显著的好处,那就是CFNetwork与系统级别的设置(如:
天线设置)以及run-loop结合得很好。
每一个线程都有自己的run-loop,因此我们可以CFNetwork当中事件源加入到run-loop中,这样就可以在线程的run-loop中处理网络事件了。
BTW,大名鼎鼎的ASIHttpRequest库就是基于CFNetwork封装的。
本文示例代码就是这样做的,源码请查看:
二,CFNetworkAPI简介
CFNetwork接口是基于C的,下面的接口用于创建一对socketstream,一个用于读取,一个用于写入:
voidCFStreamCreatePairWithSocketToHost(CFAllocatorRefalloc,CFStringRefhost,UInt32port,CFReadStreamRef*readStream,CFWriteStreamRef*writeStream);
该函数使用host以及port,CFNetwork会将该host转换为IP地址,并转换为网络字节顺序。
如果我们只需要一个socketstream,我们可以将另外一个设置为NULL。
还有另外两个“重载”的创建socketsream的接口:
CFStreamCreatePairWithSocket和
CFStreamCreatePairWithPeerSocketSignature,在这里就不一一介绍了。
注意:
这些socketstream在使用之前就如原生socket一样,必须显式地调用其open函数:
BooleanCFReadStreamOpen(CFReadStreamRefstream);
BooleanCFWriteStreamOpen(CFWriteStreamRefstream);
但与socket不同的是,这两个接口是异步的,当成功open之后,如果调用方设置了获取
kCFStreamEventOpenCompleted事件的标志的话就会其调用回调函数。
而该回调函数及其参数设置是通过如下接口进行的:
BooleanCFReadStreamSetClient(CFReadStreamRefstream,CFOptionFlagsstreamEvents,CFReadStreamClientCallBackclientCB,CFStreamClientContext*clientContext);
BooleanCFWriteStreamSetClient(CFWriteStreamRefstream,CFOptionFlagsstreamEvents,CFWriteStreamClientCallBackclientCB,CFStreamClientContext*clientContext);
该函数用于设置回调函数及相关参数。
通过
streamEvents标志来设置我们对哪些事件感兴趣;
clientCB是一个回调函数,当事件标志对应的事件发生时,该回调函数就会被调用;
clientContext是用于传递参数到回调函数中去。
当设置好回调函数之后,我们可以将socketstream当做事件源调度到run-loop中去,这样run-loop就能分发该socketstream的网络事件了。
voidCFReadStreamScheduleWithRunLoop(CFReadStreamRefstream,CFRunLoopRefrunLoop,CFStringRefrunLoopMode);
voidCFWriteStreamScheduleWithRunLoop(CFWriteStreamRefstream,CFRunLoopRefrunLoop,CFStringRefrunLoopMode);
注意,在我们不再关心该socketstream的网络事件时,记得要调用如下接口将socketstream从run-loop的事件源中移除。
voidCFReadStreamUnscheduleFromRunLoop(CFReadStreamRefstream,CFRunLoopRefrunLoop,CFStringRefrunLoopMode);
voidCFWriteStreamUnscheduleFromRunLoop(CFWriteStreamRefstream,CFRunLoopRefrunLoop,CFStringRefrunLoopMode);
当我们将socketstream的网络事件调度到run-loop之后,我们就能在回调函数中相应各种事件,比如
kCFStreamEventHasBytesAvailable
读取数据:
BooleanCFReadStreamHasBytesAvailable(CFReadStreamRefstream);
CFIndexCFReadStreamRead(CFReadStreamRefstream,UInt8*buffer,CFIndexbufferLength);
或
kCFStreamEventCanAcceptBytes写入数据:
BooleanCFWriteStreamCanAcceptBytes(CFWriteStreamRefstream);
CFIndexCFWriteStreamWrite(CFWriteStreamRefstream,constUInt8*buffer,CFIndexbufferLength);
最后,我们调用close方法关闭socketstream:
voidCFReadStreamClose(CFReadStreamRefstream);
voidCFWriteStreamClose(CFWriteStreamRefstream);
三,客户端示例代码
与socket演示类似,在这里我只演示客户端示例。
同样,我们也在一个后台线程中启动网络操作:
NSURL*url=[NSURLURLWithString:
[NSStringstringWithFormat:
@"
%@:
%@"
serverHost,serverPort]];
NSThread*backgroundThread=[[NSThreadalloc]initWithTarget:
self
selector:
@selector(loadDataFromServerWithURL:
)
object:
url];
[backgroundThreadstart];
然后在
loadDataFromServerWithURL中创建socket流,并设置其回调函数,将其加入到run-loop的事件源中,然后启动之:
-(void)loadDataFromServerWithURL:
(NSURL*)url
NSString*host=[urlhost];
NSIntegerport=[[urlport]integerValue];
//Keepareferencetoselftouseforcontrollercallbacks
//
CFStreamClientContextctx={0,(__bridgevoid*)(self),NULL,NULL,NULL};
//Getcallbacksforstreamdata,streamend,andanyerrors
CFOptionFlagsregisteredEvents=(kCFStreamEventHasBytesAvailable|kCFStreamEventEndEncountered|kCFStreamEventErrorOccurred);
//Createaread-onlysocket
CFReadStreamRefreadStream;
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault,(__bridgeCFStringRef)host,port,&
readStream,NULL);
//Schedulethestreamontherunlooptoenablecallbacks
if(CFReadStreamSetClient(readStream,registeredEvents,socketCallback,&
ctx)){
CFReadStreamScheduleWithRunLoop(readStream,CFRunLoopGetCurrent(),kCFRunLoopCommonModes);
}
else{
[selfnetworkFailedWithErrorMessage:
Failedtoassigncallbackmethod"
];
return;
//Openthestreamforreading
if(CFReadStreamOpen(readStream)==NO){
Failedtoopenreadstream"
CFErrorReferror=CFReadStreamCopyError(readStream);
if(error!
=NULL){
if(CFErrorGetCode(error)!
=0){
NSString*errorInfo=[NSStringstringWithFormat:
Failedtoconnectstream;
error'
%@'
(code%ld)"
(__bridgeNSString*)CFErrorGetDomain(error),CFErrorGetCode(error)];
errorInfo];
CFRelease(error);
NSLog(@"
Successfullyconnectedto%@"
url);
//Startprocessing
CFRunLoopRun();
参考前面的接口说明,相信你不难理解上面的代码。
前面唯一没有提到的接口就是
CFReadStreamCopyError,该接口用于获取当前的错误信息,如果没有错误则返回NULL。
CFErrorRefCFReadStreamCopyError(CFReadStreamRefstream);
CFErrorRefCFWriteStreamCopyError(CFWriteStreamRefstream);
此外,我们还可以调用如下接口获取socketstream的当前状态:
CFStreamStatusCFReadStreamGetStatus(CFReadStreamRefstream);
CFStreamStatusCFWriteStreamGetStatus(CFWriteStreamRefstream);
在上面的代码中,我们设置了当有数据可以读取,流到达结尾处时以及错误发生时调用回调函数
socketCallback:
voidsocketCallback(CFReadStreamRefstream,CFStreamEventTypeevent,void*myPtr)
KSCFNetworkViewController*controller=(__bridgeKSCF