您的位置:首页 > 移动开发 > IOS开发

iOS socket编程

2016-03-02 20:49 417 查看
//
//  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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: