上篇说到即时通讯编程选择哪种方式,笔者用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 客户端器就介绍到这里。
原文地址:http://blog.csdn.net/swift_zero/article/details/44859769