iOS网络编程实践--NSStream实现TCP Socket iPhone客户端

客户端我们使用iPhone应用程序,画面比较简单。点击发送按钮,给服务器发送一些字符串过去。点击接收按钮就会从服务器读取一些字符串,并且显示在画面上。

2

有关客户端应用的UI部分不再介绍了,我们直接看代码部分,Socket客户端可以采用CFStream或NSStream实现。为了给读者介绍更多的知识,本例我们采用NSStream实现。NSStream实现采用Objective-C语言,一些面向对象的类。

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

#import <CoreFoundation/CoreFoundation.h>

#include <sys/socket.h>

#include <netinet/in.h>

 

#define PORT 9000

 

@interface ViewController : UIViewController<NSStreamDelegate>

{

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

}

 

@property (nonatomic, retain) NSInputStream *inputStream;

@property (nonatomic, retain) NSOutputStream *outputStream;

 

@property (weak, nonatomic) IBOutlet UILabel *message;

 

- (IBAction)sendData:(id)sender;

- (IBAction)receiveData:(id)sender;

 

@end


定义属性inputStream和outputStream,它们输入流NSInputStream和输出流NSOutputStream类。它们与服务器CFStream实现中的输入流CFReadStreamRef和输出流CFWriteStreamRef对应的。

视图控制器ViewController.m的初始化网络方法initNetworkCommunication代码:

- (void)initNetworkCommunication

{

CFReadStreamRef readStream;

CFWriteStreamRef writeStream;

CFStreamCreatePairWithSocketToHost(NULL,

(CFStringRef)@”192.168.1.103″, PORT, &readStream, &writeStream);   ①

_inputStream = (__bridge_transfer NSInputStream *)readStream; ②

_outputStream = (__bridge_transfer NSOutputStream*)writeStream;  ③

[_inputStream setDelegate:self];  ④

[_outputStream setDelegate:self];  ⑤

[_inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop]

forMode:NSDefaultRunLoopMode]; ⑥

[_outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop]

forMode:NSDefaultRunLoopMode];  ⑦

[_inputStream open];  ⑧

[_outputStream open];  ⑨

}

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

/* 点击发送按钮  */

- (IBAction)sendData:(id)sender {

flag = 0;

[self initNetworkCommunication];

}

/* 点击接收按钮  */

- (IBAction)receiveData:(id)sender {

flag = 1;

[self initNetworkCommunication];

}


它们都调用initNetworkCommunication方法,并设置操作标识flag,如果flag0发送数据,flag1接收数据。

流的状态的变化触发很多事件,并回调NSStreamDelegate协议中定义的方法stream:handleEvent:,其代码如下:

-(void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {

NSString *event;

switch (streamEvent) {

case NSStreamEventNone:

event = @”NSStreamEventNone”;

break;

case NSStreamEventOpenCompleted:

event = @”NSStreamEventOpenCompleted”;

break;

case NSStreamEventHasBytesAvailable:

event = @”NSStreamEventHasBytesAvailable”;

if (flag ==1 && theStream == _inputStream) {

NSMutableData *input = [[NSMutableData alloc] init];

uint8_t buffer[1024];  ①

int len;

while([_inputStream hasBytesAvailable]) ②

{

len = [_inputStream read:buffer maxLength:sizeof(buffer)];  ③

if (len > 0)

{

[input appendBytes:buffer length:len];

}

}

NSString *resultstring = [[NSString alloc]

initWithData:input encoding:NSUTF8StringEncoding];

NSLog(@”接收:%@”,resultstring);

_message.text = resultstring;

}

break;

case NSStreamEventHasSpaceAvailable:

event = @”NSStreamEventHasSpaceAvailable”;

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

//输出

UInt8 buff[] = ”Hello Server!”; ④

[_outputStream write:buff maxLength: strlen((const char*)buff)+1]; ⑤

//关闭输出流

[_outputStream close];

}

break;

case NSStreamEventErrorOccurred:

event = @”NSStreamEventErrorOccurred”;

[self close]; ⑥

break;

case NSStreamEventEndEncountered:

event = @”NSStreamEventEndEncountered”;

NSLog(@”Error:%d:%@”,[[theStream streamError] code],

[[theStream streamError] localizedDescription]);

break;

default:

[self close];  ⑦

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

{

[_outputStream close];

[_outputStream removeFromRunLoop:[NSRunLoop currentRunLoop]

forMode:NSDefaultRunLoopMode];

[_outputStream setDelegate:nil];

[_inputStream close];

[_inputStream removeFromRunLoop:[NSRunLoop currentRunLoop]

forMode:NSDefaultRunLoopMode];

[_inputStream setDelegate:nil];

}


  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农老关【关东升】

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值