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 = @"119.29.65.70";
    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
时间: 2024-08-01 22:46:04

iOS socket编程的相关文章

IOS socket编程--Asyncsocket

iPhone的标准推荐是CFNetwork 库编程,其封装好的开源库是 cocoa AsyncSocket库,用它来简化CFNetwork的调用,它提供了异步操作 主要特性有: 队列的非阻塞的读和写,而且可选超时.你可以调用它读取和写入,它会当完成后告知你 自动的socket接收.如果你调用它接收连接,它将为每个连接启动新的实例,当然,也可以立即关闭这些连接 委托(delegate)支持.错误.连接.接收.完整的读取.完整的写入.进度以及断开连接,都可以通过委托模式调用 基于run loop的,

iOS socket编程(入门)

1.基于 C 的 BSD socket(UNIX系统中通用的网络接口) 感觉BSD socket 最容易理解,最容易入门,最为灵活     但是最难用,尤其对于大型项目 需要导入头文件 #import <sys/socket.h> #import <netdb.h> 服务器端 int listenfd, connfd; struct sockaddr_in servaddr; char buff[4096]; long n; int i=100; //创建 socket if( (

iOS网络编程笔记——Socket编程

一.什么是Socket通信: Socket是网络上的两个程序,通过一个双向的通信连接,实现数据的交换.这个双向连路的一端称为socket.socket通常用来实现客户方和服务方的连接.socket是TCP/IP协议的一个十分流行的编程接口.一个socket由一个IP地址和一个端口号唯一确定.TCP/IP协议的传输层又有两种协议:TCP(传输控制协议)和UDP(用户数据报协议).TCP是基于连接的,而UDP是无连接的:TCP对系统资源的要求较多,而UDP少:TCP保证数据的正确性而UDP可能丢包:

iOS项目开发之Socket编程

有一段时间没有认真总结和写博客了 前段时间找工作.进入工作阶段.比较少静下来认真总结,现在静下心来总结一下最近的一些心得 前言 AsyncSocket介绍 AsyncSocket详解 AsyncSocket示例 一.前言 公司的项目用到了Socket编程,之前在学习的过程当中,用到的更多的还是http请求的方式.但是既然用到了就必须学习一下,所以就在网上找一些例子,然后想自己写一个demo.可是发现很多写iOS Socket的博客并没有很详细的说明,也可能是大神们觉得其他东西都浅显易懂. 自己专

iOS从零开始学习socket编程——HTTP1.0服务器端

在前一篇文章<iOS从零开始学习socket编程--HTTP1.0客户端>中已经简单的介绍过了Socket编程和一些基本原理.并且实现了简单的iOS客户端(原文地址:http://blog.csdn.net/abc649395594/article/details/45081567) 这里再简单介绍一下如何使用OC搭建socket的服务器端.虽然这并不是一个好的解决方案,通常我们使用Java或者PHP抑或NodeJS来搭建服务器后台.但是还是有必要了解一下OC的做法,顺便加深对Socket编程

iOS从零开始学习socket编程——高并发多线程服务器

在上一篇文章<iOS从零开始学习socket编程--HTTP1.0服务器端>中我们已经简单的接触了OC搭建的HTTP服务器. (地址http://blog.csdn.net/abc649395594/article/details/45131373) 出于用户体验和鲁棒性考虑,这里把这个HTTP服务器改进成多线程的. 首先,AnsycSocket这个类是基于OC的Runloop实现的,Runloop实现了方法的异步调用但并不支持多线程. 在这里首先简单区分一下多线程和方法异步调用的区别.他们都

iOS从零开始学习socket编程——HTTP1.0客户端

在开始socket编程之前,首先需要明确几个概念: 1.网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket. 2.socket中文名为"套接字",是基于TCP/IP协议通信机制. 3.客户端的socket连接需要指定主机的ip地址和端口,ip地址类似于家庭地址,用于唯一确认一台主机,而端口类似于门牌号,用于唯一确认主机上的某一个程序. 我们模拟一次HTTP的请求.首先在终端中输入 telnet 202.118.1.7 80 我们会得到这样的提示 T

iOS开发 socket编程

二.AsyncSocket介绍 1)iOS中Socket编程的方式有哪些? -BSD Socket BSD Socket 是UNIX系统中通用的网络接口,它不仅支持各种不同的网络类型,而且也是一种内部进程之间的通信机制.而iOS系统其实本质就是UNIX,所以可以用,但是比较复杂. -CFSocket CFSocket是苹果提供给我们的使用Socket的方式,但是用起来还是会不太顺手.当然想使用的话,可以细细研究一下. -AsyncSocket 这次博客的主讲内容,也是我们在开发项目中经常会用到的

iOS开发——网络编程OC篇&amp;Socket编程

Socket编程 一.网络各个协议:TCP/IP.SOCKET.HTTP等 网络七层由下往上分别为物理层.数据链路层.网络层.传输层.会话层.表示层和应用层. 其中物理层.数据链路层和网络层通常被称作媒体层,是网络工程师所研究的对象: 传输层.会话层.表示层和应用层则被称作主机层,是用户所面向和关心的内容. http协议   对应于应用层 tcp协议    对应于传输层 ip协议     对应于网络层 三者本质上没有可比性.  何况HTTP协议是基于TCP连接的. TCP/IP是传输层协议,主要