上一篇实现了简单的 Server 端程序,服务端通过 void WriteStreamClientCallBack(CFWriteStreamRef stream, CFStreamEventType eventType, void* clientCallBackInfo) 函数向客户端发送“你好,客户端!”的消息,如果客户端接收成功的话就会显示“你好,客户端!”;需要显示服务端发送过来的消息,那么就需要定义一个UILabel输出口(IBOutlet)来显示消息;客户端还需要添加两个按钮,一个用来接收服务端消息的动作事件方法 receiveData:和发送客户端“收到啦,服务端”消息的动作事件方法 sendData:;添加关联就可以了,比较简单,下面来看一下具体实现的代码:
ViewController.h
#import <UIKit/UIKit.h>
#import <CoreFoundation/CoreFoundation.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define PORT 8734 //将端口设置为8734,可以根据具体情况改变
@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
ViewController.m
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
//初始化客户端网络连接
- (void)initNetworkCommunication
{
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
//这里需要填写 IP 地址,根据自己路由可以用的 IP来定,这里是192.168.1.103,如果不知道可以下载 IP 扫描器
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)@"192.168.1.103", PORT, &readStream, &writeStream);
self.inputStream = (__bridge_transfer NSInputStream *)readStream; //将CFStream对象转化为NSStream对象
self.outputStream = (__bridge_transfer NSOutputStream
*)writeStream; //将CFStream对象转化为NSStream对象
[self.inputStream setDelegate:self];
[self.outputStream setDelegate:self];
[self.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode]; //NSStream 方法 scheduleInRunLoop: 设置 Run Loop
[self.outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[self.inputStream open]; //NSStream 的 open 方法来打开数据流对象
[self.outputStream open];
}
//关闭数据流操作
-(void)close
{
[self.outputStream close];
[self.outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.outputStream setDelegate:nil];
[self.inputStream close];
[self.inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.inputStream setDelegate:nil];
}
//从客户端发送数据事件方法
- (IBAction)sendData:(id)sender {
flag = 0; //表示发送
[self initNetworkCommunication];
}
//从服务端接收数据事件方法
- (IBAction)receiveData:(id)sender {
flag = 1; //表示接收
[self initNetworkCommunication];
}
-(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[2048]; //读取数据准备缓冲区,本例中设置的是2048字节,这个大小会对流的读取有很大影响
int len;
while([self.inputStream hasBytesAvailable])
{
len = [self.inputStream read:buffer maxLength:sizeof(buffer)]; //读取数据到缓冲区
if (len > 0)
{
[input appendBytes:buffer length:len];
}
}
NSString *resultstring = [[NSString alloc] initWithData:input encoding:NSUTF8StringEncoding];
NSLog(@"接收:%@",resultstring);
self.message.text = resultstring;
}
break;
case NSStreamEventHasSpaceAvailable: //这个流可以接收数据的写入,在写数据时使用
event = @"NSStreamEventHasSpaceAvailable";
if (flag ==0 && theStream == _outputStream) {
//输出
UInt8 buff[] = "收到啦,服务端!"; //向服务端发送的消息
[self.outputStream write:buff maxLength: strlen((const char*)buff)+1]; //向服务端写入数据方法
//必须关闭输出流否则,服务器端一直读取不会停止,
[self.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;
}
}
@end
从代码可以知道,客户端采用的是 APPLE 自家的 NSStream 来实现的,都是比较简单的基本数据流操作。
如有哪些不对的地方,欢迎指出!