iOS 网络编程socket NSSteam的使用

Socket是一个针对TCP和UDP编程的接口,你可以借助它建立TCP连接等等。而TCP和UDP协议属于传输层 。而http是个应用层的协议,它实际上也建立在TCP协议之上。  (HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。)Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。Socket的出现只是使得程序员更方便地使用TCP/IP协议栈而已,是对TCP/IP协议的抽象,从而形成了我们知道的一些最基本的函数接口。

建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket ,另一个运行于服务器端,称为ServerSocket .套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。

1. 服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求。

2. 客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。

3. 连接接确认:当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。

以下是代码部分:


#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


                  注:原文出自http://www.cnblogs.com/mcj-coding/p/3579329.html?utm_source=tuicool

Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值