iOS 中基于Socket 的 C/S 结构的网络通信(下)

来源:互联网 发布:淘宝解除实名认证 编辑:程序博客网 时间:2024/05/16 18:41

             上一篇实现了简单的 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 来实现的,都是比较简单的基本数据流操作。

     微笑如有哪些不对的地方,欢迎指出!

1 0