即时通讯:socket 使用

   上篇说到即时通讯编程选择哪种方式,笔者用socket编写了一个仿QQ聊天的通讯应用,顺便就用这个应用介绍一个socket的使用吧

   socket与XMPP差别之处就是socket的客户端与服务器端都需要自己来搭建。XMPP 有现成的服务器跟客户端,编写测试起来就比较轻松,所以,XMPP也就成了即时通讯编程的主流了。不过介于个人兴趣,socket还是值得探究的。

  好了,就说这么多。下面就是笔者的socket应用。

  首先先介绍一下客户端这是客户端登陆界面


接下来,进行注册操作

点击注册--(向服务器端发送注册消息---下面代码会介绍

客户端注册的用户信息保存在服务器端的数据库

输入刚刚注册的用户名,密码登陆


登陆页面代码   记得先导入 AsyncSocket  框架

#import <UIKit/UIKit.h>
#import "AsyncSocket.h"

typedef void(^isSuccessBlock)(BOOL);

@interface ViewController : UIViewController
{
    
    __weak IBOutlet UIView *_contBgView;  //登陆视图
    __weak IBOutlet UITextField *_usernameField;
    __weak IBOutlet UITextField *_pwdField;

    __weak IBOutlet UITableView *_tableView;
    __weak IBOutlet UIView *_sendView;
    //信息文本
    __weak IBOutlet UITextField *_message;
}

@property(nonatomic,strong)AsyncSocket *socket; //客户端通信对象
@property(nonatomic,copy)isSuccessBlock block;  //登陆成功验证Block


//发送消息
- (IBAction)sendMessage:(UIButton *)sender;
//验证用户
- (IBAction)contentAction:(UIButton *)sender;
//注册用户
- (IBAction)registerAction:(UIButton *)sender;

@end

#import "ViewController.h"
#import "MyCell.h"
#import "registerViewController.h"
@interface ViewController ()<UITableViewDataSource,UITableViewDelegate,AsyncSocketDelegate>//设置通信代理
{
    NSMutableArray *dataArr; //存放本客户端及其它客户端消息
    NSString *username;      //验证通过后的用户名
}
@end

@implementation ViewController



- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.title=@"Cheep";
    
    _contBgView.backgroundColor=[UIColor colorWithPatternImage:[UIImage imageNamed:@"red.jpg"]];
    dataArr=[NSMutableArray array];
    _tableView.backgroundColor=[UIColor colorWithPatternImage:[UIImage imageNamed:@"chat_bg_default.jpg"]];
    _tableView.separatorStyle=UITableViewCellSeparatorStyleNone;
    _tableView.rowHeight=64;
    _sendView.backgroundColor=[UIColor colorWithPatternImage:[UIImage imageNamed:@"chat_bottom_textfield.png"]];
    //ios socket第三方框架 AsyncSocket使用简介,连接,心跳,断线,数据发送与接收
    /*
    1. socket 连接
    2. socket 断开连接与重连
    3. socket 发送与接收数据
    4. 简单使用说明
    */
   
    if (_socket == nil) {
        
        _socket=[[AsyncSocket alloc] initWithDelegate:self];
        //设定好的服务器地址跟端口
        [_socket connectToHost:@"192.168.7.19" onPort:6225 error:nil];
    }
    
    
}


//验证用户
- (IBAction)contentAction:(UIButton *)sender {
    
    /*   key  :  value
     
        doWhat:  commit(验证标记)
      username:  _usernameField.text
             ...
     */
    //将字符串转成字典样式包装发送
    NSString *dataStr= [NSString stringWithFormat:@"{\"doWhat\":\"commit\",\"username\":\"%@\",\"password\":\"%@\"}",_usernameField.text,_pwdField.text];
    NSData *data=[dataStr dataUsingEncoding:NSUTF8StringEncoding];
    /*
     data 向服务器发送的数据
     -1   请求超时时间 -1为一直等待服务器回复
     tag  是为了在回调方法中匹配发起调用的方法的,不会加在传输数据中
     */
    [_socket writeData:data withTimeout:-1 tag:0];
    //监听请求消息
    [_socket readDataWithTimeout:-1 tag:0];
    
    //服务器返回验证消息
    _block=^(BOOL result)
    {
        if (!result) {
            _usernameField.text=@"";
            _pwdField.text=@"";
        }else
        {
            //成功----记录下用户名
            username=_usernameField.text;
            _contBgView.hidden=YES; //登陆页面隐藏
            //消息页面显示
            _tableView.hidden=NO;
            _sendView.hidden=NO;
        }
    };

 
}

//注册用户
- (IBAction)registerAction:(UIButton *)sender {
    
    //注册页面控制器
    registerViewController *Ctrl=[[registerViewController alloc] init];
    
    [self presentViewController:Ctrl animated:YES completion:^{
        ;
    }];
    
    //block回调(拿到注册页面,用户名,密码)
    Ctrl.myBlock=^(NSString *textNum,NSString *textPassWord)
    {
        
        // resiger - 注册标记
        NSString *dataStr= [NSString stringWithFormat:@"{\"doWhat\":\"resiger\",\"username\":\"%@\",\"password\":\"%@\"}",textNum,textPassWord];
        NSData *data=[dataStr dataUsingEncoding:NSUTF8StringEncoding];
        //向服务器发送注册请求,并监听请求信息
        [_socket writeData:data withTimeout:-1 tag:0];
        [_socket readDataWithTimeout:-1 tag:0];
        
    };
    
    
}



//向服务器发送消息
- (IBAction)sendMessage:(UIButton *)sender {
    
    
    if(_message.text.length >0)
    {
        //显示在本客户端UI的消息
        NSDictionary *dic=[NSDictionary dictionary];
        dic=@{
              @"socket":@"client",
              @"username":username,
              @"message":_message.text
              };
        [dataArr addObject:dic];
        //插入数据到最后一个单元格
        NSIndexPath *index=[NSIndexPath indexPathForRow:dataArr.count-1 inSection:0];
        [_tableView insertRowsAtIndexPaths:@[index] withRowAnimation:UITableViewRowAnimationFade];
        //滚动到最后一个单元格
        [_tableView scrollToRowAtIndexPath:index atScrollPosition:UITableViewScrollPositionBottom animated:YES];
        
        /*
         (内容包括 :内容标记,本客户端用户名,是否是客户端,发送的内容)当然自己可以定制,只要在服务器端也做相应的接收就可以
         */
        
        NSString *message= [NSString stringWithFormat:@"{\"doWhat\":\"message\",\"username\":\"%@\",\"socket\":\"client\",\"message\":\"%@\"}",username,_message.text];
        NSData *data=[message dataUsingEncoding:NSUTF8StringEncoding];
        //向服务器发送聊天消息
        [_socket writeData:data withTimeout:-1 tag:0];
        [_socket readDataWithTimeout:-1 tag:0];

        _message.text=@"";
    }
}




#pragma mark- UITableView dataSource delegate

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return dataArr.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *intenty = @"UITableViewCell";
    
    MyCell*cell = [tableView dequeueReusableCellWithIdentifier:intenty];
 
    if (cell == nil) {
        
        cell=[[[NSBundle mainBundle] loadNibNamed:@"MyCell" owner:self options:nil] lastObject];
    }
    NSDictionary *message =dataArr[indexPath.row];
    //将model交给视图去显示
    cell.message=message;

    return cell;
}


#pragma mark - AsyncSocketDelegate


//1.客户端连接服务器调用的协议方法
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
    //监听服务端socket消息
    [sock readDataWithTimeout:-1 tag:0];
    
}

//2.接受服务器发送过来的数据(读取数据)
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
    //服务器处理客户端发送的消息,相应的返回客户端能识别的消息(比如,上面客户端向服务器发送字典消息,服务器也返回相应的字典消息)
    NSDictionary *dic=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
//    NSLog(@"%@",dic);
    NSString *dowhat=[dic objectForKey:@"doWhat"]; //内容标记
    NSString *type=[dic objectForKey:@"type"];    //处理结果
    
    if ([dowhat isEqualToString:@"commit"]) //登陆验证返回消息
    {
        if ([type integerValue]==1) {
            NSLog(@"验证成功");
            _block(YES);
        }else
        {
            NSLog(@"验证失败");
        }
    }else if ([dowhat isEqualToString:@"resiger"]) //注册返回消息
    {
        if ([type integerValue]==2) {
            
            NSLog(@"注册成功");
            
        }else
        {
         
        }
        
    }else if([dowhat isEqualToString:@"message"]) //聊天消息返回的消息
    {
        //拿到其他客户端发送的消息,
        NSString *message=[dic objectForKey:@"message"];
        NSString *fromusername=[dic objectForKey:@"username"];
//        NSString *socket=[dic objectForKey:@"socket"];
        dic=@{
              @"socket":@"server",
              @"username":fromusername,
              @"message":message
              };
        [dataArr addObject:dic];
        
        //UI操作放在主线程上
        dispatch_async(dispatch_get_main_queue(), ^{
            //插入数据到最后一个单元格
            NSIndexPath *index=[NSIndexPath indexPathForRow:dataArr.count-1 inSection:0];
            [_tableView insertRowsAtIndexPaths:@[index] withRowAnimation:UITableViewRowAnimationFade];
            //滚动到最后一个单元格
            [_tableView scrollToRowAtIndexPath:index atScrollPosition:UITableViewScrollPositionBottom animated:YES];
        });
        
        
    }
    //继续监听服务器发来的消息
    [sock readDataWithTimeout:-1 tag:0];
}

@end

注册页面在视图返回登陆页面的时候记得使用Block回调即可

    //调用--先判断
    if (self.myBlock != nil) {
        
        self.myBlock(_fieldNum.text,_fieldPassWord.text);
    }
    //布局子视图 需判断消息是否为自己发送
    if ([what isEqualToString:@"client"]) {
        
        _iconImage.frame = CGRectMake(Kw - 50, 10, 40, 40);
        _bgImage.frame = CGRectMake(Kw-50-(size.width + 30)-10, 10, size.width + 30, size.height + 30);
        _contText.frame = CGRectMake(Kw-50-size.width-30, 20, size.width, size.height);
         _usernameLabel.frame=CGRectMake(Kw-70, 1, 100, 17);
        
    }else if([what isEqualToString:@"server"])
    {
        
        _iconImage.frame = CGRectMake(10, 10, 40, 40);
        _bgImage.frame = CGRectMake(60, 10, size.width + 30, size.height + 30);
        _contText.frame = CGRectMake(80, 20, size.width, size.height);
        _usernameLabel.frame=CGRectMake(52, 1, 100, 17);
    }
单元格布局根据字典内的消息的出处,判断该怎么布局。

socket 客户端器就介绍到这里。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值