iOS 即时通讯,简单socket网络编程一<socket 底层>

本篇文章简单介绍一下iOS的socket即时通讯底层的实现。

<1>socket简单的本地服务器的搭建,大家可以参考博客http://www.jianshu.com/p/39a68332e19f   。

<2>iOS  socket编程的底层是通过调用C语言的函数,并通过OC和C语言的桥接,通过输入输出流进行数据读写,进行及时通讯。下面是一个简单的socket网络编程的demo。
//
//  ViewController.m
//  SocketTest
//
//  Created by fe on 16/9/4.
//  Copyright © 2016年 fe. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()<NSStreamDelegate,UITextFieldDelegate,UITableViewDelegate,UITableViewDataSource>

@property(nonatomic,strong) NSInputStream *inputStream;
@property(nonatomic,strong) NSOutputStream *outputStream;
//拿到输入框文本,以便修改位置
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *textFieldCounterbottom;
//用于存放聊天内容的数组
@property (nonatomic,strong) NSMutableArray *msgArry;
@property (weak, nonatomic) IBOutlet UITableView *msgTableView;

@end

@implementation ViewController

- (NSMutableArray *)msgArry
{
    if (!_msgArry) {
        _msgArry = [[NSMutableArray alloc] init];
    }
    return _msgArry;
}
- (void)viewDidLoad {
    [super viewDidLoad];

    //监听键盘
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(theKeyBoardDidChanged:) name:UIKeyboardWillChangeFrameNotification object:nil];

    
}
#pragma mark - NSStreamDelegate
-(void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
//    NSStreamEventOpenCompleted = 1UL << 0,//输入输出流打开完成
//    NSStreamEventHasBytesAvailable = 1UL << 1,//有字节可读
//    NSStreamEventHasSpaceAvailable = 1UL << 2,//可以发送字节
//    NSStreamEventErrorOccurred = 1UL << 3,//链接出现了错误
//    NSStreamEventEndEncountered = 1UL << 4//结束
    switch (eventCode) {
        case NSStreamEventOpenCompleted:
            NSLog(@"输入输出流打开完成");
            break;
        case NSStreamEventHasBytesAvailable:
            NSLog(@"有字节可读");
            [self readData];
            break;
        case NSStreamEventHasSpaceAvailable:
            NSLog(@"可以发送字节");
            
            break;
        case NSStreamEventErrorOccurred:
            NSLog(@"链接出现了错误");
            
            break;
        case NSStreamEventEndEncountered:
            NSLog(@"结束");
            //关闭输入输出流
            [self.inputStream close];
            [self.outputStream close];
            //从主循环移除
            [self.inputStream removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
            [self.outputStream removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
            break;
            
        default:
            break;
    }
}
- (IBAction)connectToInternet:(id)sender {
    //1:建立连接
    NSString *localHost = @"127.0.0.1";//本机地址
    int port = 12345;//服务器端口
    //定义c语言输入输出流
    CFReadStreamRef readStream;
    CFWriteStreamRef writeStream;
    CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)(localHost), port, &readStream, &writeStream);
    //把c语言的输入输出流转化为oc对象
    self.inputStream = (__bridge NSInputStream *)readStream;
    self.outputStream = (__bridge NSOutputStream *)(writeStream);
    
    //设置输入输出流的代理
    self.inputStream.delegate = self;
    self.outputStream.delegate = self;
    //把输入输出流添加到主运行循环
    [self.inputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
    [self.outputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
    //打开输入输出流
    [self.inputStream open];
    [self.outputStream open];
}
- (IBAction)login:(id)sender {
    
    //2:收发数据
    //2.1:登陆  发送用户名和密码 这里我们只简单的发送一个用户名进行登陆
    //如果登陆发送的数据格式为 “iam:zhengyanfneg”
    //如果发送消息发送的数据格式为 “msg:How are you”
    //登陆指令
    NSString *loginStr = @"iam:zhengyanfeng";
    //将字符串转化为data
    NSData *loginData = [loginStr dataUsingEncoding:NSUTF8StringEncoding];
    
    [self.outputStream write:loginData.bytes maxLength:loginData.length];
    
    
    
}
#pragma mark - 读取服务器返回的数据
- (void)readData
{
    //建立数据缓冲区可以放1024个字节(字节数组)
    uint8_t buf[1024];
    //length 返回的实际字节长度
    NSInteger length =[self.inputStream read:buf maxLength:sizeof(buf)];
    //把字节转化成字符串
    NSData *receiveData =[NSData dataWithBytes:buf length:length];
    NSString *receiveStr = [[NSString alloc] initWithData:receiveData encoding:NSUTF8StringEncoding];
    [self reloadDataWithString:receiveStr];
    
}
#pragma mark - UITextFieldDelegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{

    //发送聊天数据
    NSString *mesStr = [NSString stringWithFormat:@"msg:%@",textField.text];
    [self reloadDataWithString:mesStr];
    NSData *strData = [mesStr dataUsingEncoding:NSUTF8StringEncoding];
    [self.outputStream write:strData.bytes maxLength:strData.length];
    textField.text = nil;
    return YES;
}
//监听键盘位置变化的方法
- (void)theKeyBoardDidChanged:(NSNotification *)noti{
    NSLog(@"%@",noti.userInfo);
    CGFloat windowH = [UIScreen mainScreen].bounds.size.height;
    CGRect keyboardFrame = [noti.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    CGFloat keyboardY = keyboardFrame.origin.y;
    self.textFieldCounterbottom.constant = windowH - keyboardY;
}
#pragma mark - UITableViewDelegate UITableViewDataSource
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return self.msgArry.count;
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *const reuseID = @"socketCell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseID];

    cell.textLabel.text = self.msgArry[indexPath.row];
    return cell;
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    [self.view endEditing:YES];
}
//向聊天数组添加数据并刷新表格
- (void)reloadDataWithString:(NSString *)msgStr
{
    [self.msgArry addObject:msgStr];
    [self.msgTableView reloadData];
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:(self.msgArry.count -1 ) inSection:0];
    [self.msgTableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
@end


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
环境:Windows XP SP3、 VC++ 6.0、 Windows 2003 SDK 使用步骤: 1、下载解压之后,使用VC++ 6.0打开两个工程:一个是SocketServer和一个ClientSocket工程。 2、首先运行服务器端工程,选默认的端口1008 3、然后运行客户端工程,选默认的端口1008和默认的服务器地址 4、再运行多个客户端进程 5、如果一切正常,可以每个客户端的消息发送,我们可以在服务端和各个客户端同步看到消息 实现一个服务器对多个客户端的关键是,在服务端的使用集合CPtrList类用保存客户端的socket对象,思想与Java中的编程思想一样,只不过Java中会使用多线程技术,在Vector集合保存客户端的socket对象,而MFC框架提供了CSocket类,它是一个异步通信的类,所以看上去代码比较Java的多线程代码简单的实现了一个对多的即时通讯功能。另外,MFC提供了CSocketFile类和CArchive类与CSocket类实现了C++的网络通讯编程功能。 本示例注释非常详细,所有的辅助类都放一个util目录中,然后在工程中分了一个目录来管理这些辅助类,使用代码非常清晰。手动书写部分的代码是按Java的规范书写,当然其它代码由IDE生成的,所以是MS的风格,所以当你看代码时,只要是使用“骆驮命名法”的方法都是本人书写的功能性代码。 参看的思路:在服务端要从回调方法onAccept读起;而客户端代码主要从OnSendButton方法读起,即可理解整个代码的意思。 阅读对象:具有Java的Socket编程经验的人员,并且希望能够书写出比Java效率更高的即时通讯程序的人员

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值