• iOS socket编程


    //
    //  ViewController.m
    //  socket
    //
    //  Created by emerys on 16/3/2.
    //  Copyright © 2016年 Emerys. All rights reserved.
    //
    
    #import "ViewController.h"
    
    #warning 0000前面四位为消息长度,后接消息,最后以#结束
    
    @interface ViewController ()<NSStreamDelegate,UITableViewDataSource>
    {
        // 输入流
        NSInputStream *inputStream;
        //  输出流
        NSOutputStream *outputStream;
    }
    // 用以存储聊天记录,键值为 client_date/service_date
    @property (nonatomic,strong) NSMutableArray *history;
    
    @property (nonatomic,copy) NSString *msg;
    
    @property (weak, nonatomic) IBOutlet UITextField *inputTextField;
    @property (weak, nonatomic) IBOutlet UIButton *sendMsgButton;
    @property (weak, nonatomic) IBOutlet UITableView *historyTableView;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        [self loadHistory];
        
        self.historyTableView.dataSource = self;
        
        [self connect];
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    /**
     * @brief 懒加载字典
     */
    -(NSMutableArray *)history{
        if (!_history) {
            _history = [NSMutableArray array];
        }
        return _history;
    }
    /**
     * @brief 开启链接
     */
    -(void)connect{
        // 1.建立连接
        NSString *host = @"127.0.0.1";
        int port = 9868;
    
        // 定义C语言输入输出流
        CFReadStreamRef readStream;
        CFWriteStreamRef writeStream;
        CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)host, port, &readStream, &writeStream);
        
        // 把C语言的输入输出流转化成OC对象
        inputStream = (__bridge NSInputStream *)(readStream);
        outputStream = (__bridge NSOutputStream *)(writeStream);
        // 设置代理
        inputStream.delegate = self;
        outputStream.delegate = self;
        
        // 把输入输入流添加到主运行循环
        // 不添加主运行循环 代理有可能不工作
        [inputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
        [outputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
        
         // 打开输入输出流
        [inputStream open];
        [outputStream open];
    }
    /**
     * @brief 开启输入/出流监听
     */
    -(void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode{
    
        switch (eventCode) {
            case NSStreamEventNone:{
                
            }
                break;
            case NSStreamEventOpenCompleted:{
                // 打开
    //            [self showAlertMessage:@"连接服务器成功"];
                NSLog(@"ok");
            }
                break;
            case NSStreamEventHasBytesAvailable:{
                // 有数据可读
                [self readData];
            }
                break;
                
    
            case NSStreamEventHasSpaceAvailable:{
                // 可发
                if (self.msg) {
                    [self writeData];
                }
                
            }
                break;
                
    
            case NSStreamEventErrorOccurred:{
                // 链接错误,那么重新链接
                [self connect];
            }
                break;
                
    
            case NSStreamEventEndEncountered:{
                // 结束链接,关闭流,从主运行循环移开
                [inputStream close];
                [outputStream close];
                
                [inputStream removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
                [outputStream removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
            }
                break;
                
            default:
                break;
        }
        
    }
    /**
     * @brief 读取数据
     */
    -(void)readData{
        // 设置1024字节的缓冲区
        uint8_t buf[1024];
        
        NSInteger length = [inputStream read:buf maxLength:1024];
        
        if (length > 0) {
            NSData *data = [NSData dataWithBytes:buf length:length];
    #warning 在此编码方式不同可能会引起str为空,添加进数组时程序崩溃
            // gb2312
            NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding (kCFStringEncodingGB_18030_2000);
            
            NSString *str = [[NSString alloc] initWithData:data encoding:encoding];
            
    //        NSLog(@"%@",str);
            [self.history addObject:str];
            [self.historyTableView reloadData];
            [self saveData];
        }
        
    }
    /**
     * @brief 发送数据
     */
    -(void)writeData{
        NSString *msg = self.msg;
        NSString *head;
        NSUInteger msgLength = msg.length;
        // 超出最大限制,或没有数据, 则不发
        if (!msgLength && msgLength >= 10000) {
            [self showAlertMessage:@"您发送的数据长度超出限度,请重新编辑"];
        }else{
            if (msgLength < 10) {
                head = [NSString stringWithFormat:@"000%li",msgLength];
            }else if(msgLength >= 10 && msgLength < 100){
                head = [NSString stringWithFormat:@"00%li",msgLength];
            }else if (msgLength >= 100 && msgLength < 1000){
                head = [NSString stringWithFormat:@"0%li",msgLength];
            }else if (msgLength >= 1000 && msgLength < 10000){
                head = [NSString stringWithFormat:@"%li",msgLength];
            }
            NSString *str = [NSString stringWithFormat:@"%@%@#",head,msg];
            
            NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
            
            [outputStream write:data.bytes maxLength:data.length];
            self.msg = nil;
            [self.history addObject:msg];
            [self.historyTableView reloadData];
            [self saveData];
        }
    
    }
    /**
     * @brief 显示一些提示信息
     * @param msg 表示将要显示的信息
     */
    -(void)showAlertMessage:(NSString *)msg{
        __block UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"温馨提示" message:msg preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction *action = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            [alert dismissViewControllerAnimated:YES completion:nil];
            alert = nil;
        }];
        [alert addAction:action];
        [self presentViewController:alert animated:YES completion:nil];
    }
    /**
     * @brief 发送数据按钮回调
     */
    - (IBAction)senMessage:(id)sender {
        NSString *msg = self.inputTextField.text;
    //    NSString *head;
        NSUInteger msgLength = msg.length;
        // 超出最大限制或没有数据, 则不发
        if (!msgLength && msgLength >= 10000) {
            [self showAlertMessage:@"您发送的数据长度超出限度,请重新编辑"];
        }else{
            self.msg = msg;
            [self stream:outputStream handleEvent:NSStreamEventHasSpaceAvailable];
        }
    
    }
    
    
    #pragma mark 数据源
    -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
        return 1;
    }
    -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
        return [self.history count];
    }
    -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
        if (!cell) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
        }
        NSString *str = self.history[indexPath.row];
        cell.textLabel.text = str;
        return cell;
    }
    /**
     * @brief 检测文件是否存在
     */
    -(BOOL)checkFile{
    //    NSString *dPath = [NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES) firstObject];
        NSString *home = NSHomeDirectory();
        NSString *path = [home stringByAppendingPathComponent:@"documents/history.plist"];
    
        NSFileManager *manager = [NSFileManager defaultManager];
        return [manager fileExistsAtPath:path];
    }
    
    /**
     * @brief 保存数据到本地
     */
    -(void)saveData{
      
        if (self.history.count) {
    
            NSString *home = NSHomeDirectory();
            NSString *path = [home stringByAppendingPathComponent:@"documents/history.plist"];
            if([self.history writeToFile:path atomically:YES]){
                NSLog(@"save ok");
            }else{
                NSLog(@"save error");
            }
    
        }
        
       
    }
    /**
     * @brief 读取历史数据
     */
    -(void)loadHistory{
        NSString *home = NSHomeDirectory();
        NSString *path = [home stringByAppendingPathComponent:@"documents/history.plist"];
        
        NSArray *array = [NSArray arrayWithContentsOfFile:path];
        if (array.count) {
            [self.history addObjectsFromArray:array];
            [self.historyTableView reloadData];
        }
    
    }
    
    
    
    @end
  • 相关阅读:
    .net 日期格式化
    grunt 上手
    设计模式的认识
    顺时针打印矩阵
    WCF 框架运行时类图
    Python闭包详解
    软件用了那些技术
    zoj 1610 Count the Colors(线段树延迟更新)
    快速提高自己的技术的办法?有两个方法
    纯win32实现PNG图片透明窗体
  • 原文地址:https://www.cnblogs.com/buakaw/p/5236459.html
Copyright © 2020-2023  润新知