#import "ViewController.h"
@interface ViewController ()
<NSStreamDelegate, UITextFieldDelegate,
UITableViewDataSource>
{
NSInputStream
*_inputStream; // 输入流
NSOutputStream
*_outputStream; // 输出流
NSMutableArray
*_dataList;
}
@property (weak, nonatomic) IBOutlet UITextField
*hostName;
@property (weak, nonatomic) IBOutlet UITextField
*portText;
@property (weak, nonatomic) IBOutlet UITextField
*nickNameText;
@property (weak, nonatomic) IBOutlet UITextField
*messageText;
@property (weak, nonatomic) IBOutlet UITableView
*tableView;
@end
@implementation
ViewController
/**
通过Scoket可以实现所有的网络功能:包括:GET、POST、PUT、DELETE
最主要的应用场景是:自定义的协议,编写自由的网络应用!
==========================================================
Socket
的难点:
1.
因为所有的输入输出都是在一个代理方法中调用,随着自定义协议的复杂度的提高,
程序编写难度势必要大幅度提升。
2. 多线程的处理!
示例代码中,输入流合输出流都添加到了主运行循环,如果应用过于复杂,将影响主线程程序的性能
因此,需要使用另外一个运行循环,专门管理输入输出流。
代理方法的工作是对数据的输入输出流进行“解析”,解析工作同样不需要影响到主线程的工作。
多线程方面的处理,是Socket的一大难点!
可以使用第三方框架!会在XMPP项目中隆重登场!
============================================================
程序员写程序最主要的目的是用来阅读的,捎带着把程序的功能给实现了。
SSL
安全漏洞,goto fail。
*/
-
(void)viewDidLoad
{
[super
viewDidLoad];
_dataList =
[NSMutableArray array];
}
- (BOOL)textFieldShouldReturn:(UITextField
*)textField
{
//
确认真的输入了文字,再发送消息给服务器
if (textField.text.length > 0)
{
//
发送登录消息
NSString *msg = [NSString
stringWithFormat:@"msg:%@",
textField.text];
//
在网络上发送的是二进制数据
NSData *data = [msg
dataUsingEncoding:NSUTF8StringEncoding];
//
发送数据,直接往输入流写数据
[_outputStream
write:data.bytes maxLength:data.length];
}
return YES;
}
-
(NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return
_dataList.count;
}
- (UITableViewCell *)tableView:(UITableView
*)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath
{
static NSString *ID =
@"Cell";
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:ID];
cell.textLabel.text =
_dataList[indexPath.row];
return
cell;
}
#pragma mark - 私有方法
#pragma mark 连接到服务器
-
(void)connectToServer:(NSString *)hostName
port:(NSInteger)port
{
//
要进行Socket开发,以下代码都是固定的
// 设置网络
CFReadStreamRef readStream;
CFWriteStreamRef
writeStream;
//
CF框架是C语言的框架,在OC中的Socet方法,C语言部分的代码,总共就5行
//
此方法可以连接到服务器,并分配输入流和输出流的内存空间
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)hostName, port,
&readStream, &writeStream);
// 记录已经分配的输入流和输出流
_inputStream = (__bridge NSInputStream
*)readStream;
_outputStream = (__bridge NSOutputStream
*)writeStream;
//
设置代理,监听输入流和输出流中的变化
_inputStream.delegate =
self;
_outputStream.delegate = self;
//
Scoket是建立的长连接,需要将输入输出流添加到主运行循环
//
如果不将流加入主运行循环,delegate拒绝工作
[_inputStream
scheduleInRunLoop:[NSRunLoop mainRunLoop]
forMode:NSDefaultRunLoopMode];
[_outputStream
scheduleInRunLoop:[NSRunLoop mainRunLoop]
forMode:NSDefaultRunLoopMode];
//
打开输入流和输出流,准备开始文件读写操作
[_inputStream
open];
[_outputStream open];
}
#pragma mark
NSStream的代理方法
/**
NSStreamEventNone =
0,
// 无事件
NSStreamEventOpenCompleted = 1UL <<
0, //
建立连接完成
NSStreamEventHasBytesAvailable = 1UL <<
1, //
有可读的字节,接收到了数据,可以读了
NSStreamEventHasSpaceAvailable = 1UL <<
2, //
可以使用输出流的空间,此时可以发送数据给服务器
NSStreamEventErrorOccurred = 1UL <<
3, //
发生错误
NSStreamEventEndEncountered = 1UL <<
4 //
流结束事件,在此事件中负责做销毁工作
*/
- (void)stream:(NSStream *)aStream
handleEvent:(NSStreamEvent)eventCode
{
NSLog(@"%d",
eventCode);
switch (eventCode)
{
case
NSStreamEventOpenCompleted:
NSLog(@"连接完成");
break;
case
NSStreamEventHasBytesAvailable:
NSLog(@"有可读字节");
//
读从服务器接收到得数据,从输入流中读取
//
先开辟一段缓冲区以读取数据,用空间来换取程序的简单
uint8_t
buffer[1024];
//
read返回的是输入流缓冲区中实际存储的字节数
NSInteger len = [_inputStream read:buffer
maxLength:sizeof(buffer)];
if
(len > 0) { //
读到数据
//
将buffer中的数据,转换成字符串,输出
NSString *str = [[NSString alloc] initWithBytes:buffer length:len
encoding:NSUTF8StringEncoding];
//
将接收到的内容添加到数组
[_dataList
addObject:str];
//
刷新表格
[_tableView
reloadData];
}
break;
case
NSStreamEventHasSpaceAvailable:
NSLog(@"可以写入数据");
break;
case
NSStreamEventErrorOccurred:
NSLog(@"发生错误");
break;
case
NSStreamEventEndEncountered:
NSLog(@"流结束");
// 做善后工作
//
关闭流的同时,将流从主运行循环中删除
[aStream
close];
[aStream removeFromRunLoop:[NSRunLoop mainRunLoop]
forMode:NSDefaultRunLoopMode];
default:
break;
}
}
#pragma mark - Action
#pragma mark
登录到聊天室
- (IBAction)login
{
NSString *hostName =
_hostName.text;
NSInteger port = [_portText.text
integerValue];
[self
connectToServer:hostName port:port];
// 发送登录消息
NSString *msg =
[NSString stringWithFormat:@"iam:%@", _nickNameText.text];
// 在网络上发送的是二进制数据
NSData *data = [msg
dataUsingEncoding:NSUTF8StringEncoding];
// 发送数据,直接往输入流写数据
[_outputStream write:data.bytes
maxLength:data.length];
}
@end
IOS - socket 编程初体验,布布扣,bubuko.com
原文:http://www.cnblogs.com/mcj-coding/p/3579329.html