ios网络编程.docx

上传人:b****5 文档编号:6868511 上传时间:2023-01-11 格式:DOCX 页数:24 大小:94.04KB
下载 相关 举报
ios网络编程.docx_第1页
第1页 / 共24页
ios网络编程.docx_第2页
第2页 / 共24页
ios网络编程.docx_第3页
第3页 / 共24页
ios网络编程.docx_第4页
第4页 / 共24页
ios网络编程.docx_第5页
第5页 / 共24页
点击查看更多>>
下载资源
资源描述

ios网络编程.docx

《ios网络编程.docx》由会员分享,可在线阅读,更多相关《ios网络编程.docx(24页珍藏版)》请在冰豆网上搜索。

ios网络编程.docx

ios网络编程

iOS网络编程实践--NSStream实现TCPSocketiPhone客户端

客户端我们使用iPhone应用程序,画面比较简单。

点击发送按钮,给服务器发送一些字符串过去。

点击接收按钮就会从服务器读取一些字符串,并且显示在画面上。

 

有关客户端应用的UI部分不再介绍了,我们直接看代码部分,Socket客户端可以采用CFStream或NSStream实现,CFStream实现方式与服务器端基本一样。

为了给读者介绍更多的知识,本例我们采用NSStream实现。

NSStream实现采用Objective-C语言,一些面向对象的类。

下面我们看看客户端视图控制器ViewController.h

#import

#include

#include

#definePORT9000

@interfaceViewController:

UIViewController

{

intflag;//操作标志0为发送1为接收

}

@property(nonatomic,retain)NSInputStream*inputStream;

@property(nonatomic,retain)NSOutputStream*outputStream;

@property(weak,nonatomic)IBOutletUILabel*message;

-(IBAction)sendData:

(id)sender;

-(IBAction)receiveData:

(id)sender;

@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:

self];⑤

[_inputStreamscheduleInRunLoop:

[NSRunLoopcurrentRunLoop]

forMode:

NSDefaultRunLoopMode];⑥

[_outputStreamscheduleInRunLoop:

[NSRunLoopcurrentRunLoop]

forMode:

NSDefaultRunLoopMode];⑦

[_inputStreamopen];⑧

[_outputStreamopen];⑨

}

 

 

点击发送和接收按钮触发的方法如下:

/*点击发送按钮*/

-(IBAction)sendData:

(id)sender{

flag=0;

[selfinitNetworkCommunication];

}

/*点击接收按钮*/

-(IBAction)receiveData:

(id)sender{

flag=1;

[selfinitNetworkCommunication];

}

 

它们都调用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”;

break;

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;

}

break;

caseNSStreamEventHasSpaceAvailable:

event=@”NSStreamEventHasSpaceAvailable”;

if(flag==0&&theStream==_outputStream){

//输出

UInt8buff[]=”HelloServer!

”;④

[_outputStreamwrite:

buffmaxLength:

strlen((constchar*)buff)+1];⑤

//关闭输出流

[_outputStreamclose];

}

break;

caseNSStreamEventErrorOccurred:

event=@”NSStreamEventErrorOccurred”;

[selfclose];⑥

break;

caseNSStreamEventEndEncountered:

event=@”NSStreamEventEndEncountered”;

NSLog(@”Error:

%d:

%@”,[[theStreamstreamError]code],

[[theStreamstreamError]localizedDescription]);

break;

default:

[selfclose];⑦

event=@”Unknown”;

break;

}

NSLog(@”event——%@”,event);

}

 

在读取数据分支(NSStreamEventHasBytesAvailable)中,代码第①行为读取数据准备缓冲区,本例中设置的是1024个字节,这个大小会对流的读取有很多的影响。

第②行代码使用hasBytesAvailable方法判断是否流有数据可以读,如果有可读数据就进行循环读取。

第③行代码使用流的read:

maxLength:

方法读取数据到缓冲区,第1个参数是缓冲区对象buffer,第2个参数是读取的缓冲区的字节长度。

在写入数据分支(NSStreamEventHasSpaceAvailable)中,代码第④行是要写入的数据,第⑤行代码[_outputStream write:

buff maxLength:

 strlen((const char*)buff)+1]是写如数据方法。

第⑥和第⑦行代码[self close]调用close方法关闭,close方法代码如下:

-(void)close

{

[_outputStreamclose];

[_outputStreamremoveFromRunLoop:

[NSRunLoopcurrentRunLoop]

forMode:

NSDefaultRunLoopMode];

[_outputStreamsetDelegate:

nil];

[_inputStreamclose];

[_inputStreamremoveFromRunLoop:

[NSRunLoopcurrentRunLoop]

forMode:

NSDefaultRunLoopMode];

[_inputStreamsetDelegate:

nil];

}

[深入浅出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){

[selfnetworkFailedWithErrorMessage:

@"Failedtoopenreadstream"];

return;

}

CFErrorReferror=CFReadStreamCopyError(readStream);

if(error!

=NULL){

if(CFErrorGetCode(error)!

=0){

NSString*errorInfo=[NSStringstringWithFormat:

@"Failedtoconnectstream;error'%@'(code%ld)",(__bridgeNSString*)CFErrorGetDomain(error),CFErrorGetCode(error)];

[selfnetworkFailedWithErrorMessage:

errorInfo];

}

CFRelease(error);

return;

}

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

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育 > 数学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1