编写群聊服务端代码,稍加改写之前的10086服务端的代码,如下:
//
// ServiceListener.m
#import "ServiceListener.h"
#import "GCDAsyncSocket.h"
@interface ServiceListener() <GCDAsyncSocketDelegate>
/**
* 服务器端的socket对象
*/
@property(nonatomic,strong)GCDAsyncSocket *serviceScoket;
/**
* 保存所有客户端的socket对象的数组
*/
@property(nonatomic,strong)NSMutableArray *clientSockets;
@end
@implementation ServiceListener
- (NSMutableArray *)clientSockets
{
if (!_clientSockets) {
_clientSockets = [NSMutableArray array];
}
return _clientSockets;
}
/**
* 开启10086服务
*/
- (void)start
{
// 1.创建一个socket对象
// serviceScoket: 服务端的scoket只监听有没有客户端请求连接
GCDAsyncSocket *serviceScoket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(0, 0)];
self.serviceScoket = serviceScoket;
// 2.绑定端口,并开启监听
// 代表10086服务以及启动
NSError *error = nil;
[serviceScoket acceptOnPort:5288 error:&error];
if (!error) {
NSLog(@"服务开启成功");
}else{
NSLog(@"服务开启失败%@",error);
}
}
#pragma mark - <GCDAsyncSocketDelegate>
/**
* 有客户端的socket连接到服务器就会调用这个方法
*
* @param sock 服务器端的socket
* @param newSocket 客户端的socket
*/
- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket
{
// 打印客户端主机和端口号
NSLog(@"host:%@ port:%hu",newSocket.connectedHost,newSocket.connectedPort);
// 1.保存客户端的socket
[self.clientSockets addObject:newSocket];
// 2.监听客户端有没有数据上传
// timeout -1:代表不超时
// tag 标识:现在不用就写0
[newSocket readDataWithTimeout:-1 tag:0];
NSLog(@"当前有%zd个客户端连接",self.clientSockets.count);
}
/**
* 读取客户端请求的数据
*
* @param sock 客户端的socket
* @param data 二进制数据
* @param tag 标识
*/
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
// 1.把NSData转成NSString
NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
// 2.把当前客户端的数据转发给其他客户端
for (GCDAsyncSocket *socket in self.clientSockets) {
if (socket != sock) {
[socket writeData:data withTimeout:-1 tag:0];
}
}
#warning 每次读完数据后,都要调用一次监听数据的方法(CocoaAsyncSocket框架是这样设计的)
[sock readDataWithTimeout:-1 tag:0];
}
@end
运行服务端程序后,开2个终端连接,演示如下:
至此,群聊的雏形已现。下面我们编写客户端代码,通过iOS应用程序发送消息给服务器端。
编写群聊iOS客户端:
//
// ViewController.m
#import "ViewController.h"
#import "GCDAsyncSocket.h"
@interface ViewController () <GCDAsyncSocketDelegate,UITableViewDataSource>
@property (weak, nonatomic) IBOutlet UITextField *inputField;
- (IBAction)send:(UIButton *)sender;
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property(nonatomic,strong)GCDAsyncSocket *clientSocket;
/**
* cell数据源
*/
@property(nonatomic,strong)NSMutableArray *dataSources;
@end
@implementation ViewController
- (NSMutableArray *)dataSources
{
if (!_dataSources) {
_dataSources = [NSMutableArray array];
}
return _dataSources;
}
- (void)viewDidLoad {
// 1.连接到服务器端
// 1.1创建一个客户端的socket对象
GCDAsyncSocket *clientSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(0, 0)];
self.clientSocket = clientSocket;
// 1.2发送连接请求
NSError *error = nil;
[clientSocket connectToHost:@"127.0.0.1" onPort:5288 error:&error];
// 2.发送消息和接收消息
}
- (IBAction)send:(UIButton *)sender {
NSString *str = self.inputField.text;
if (str.length == 0) {
return;
}
// 把消息添加到数据源数组
[self.dataSources addObject:str];
[self.tableView reloadData];
[self.clientSocket writeData:[str dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:0];
}
#pragma mark - <GCDAsyncSocketDelegate>
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
{
NSLog(@"与服务器连接成功");
// 监听读取数据
[sock readDataWithTimeout:-1 tag:0];
}
/**
* 读取数据
*/
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
// NSLog(@"读取到的数据 %@",str);
// 把消息添加到数据源数组
if(str){
[self.dataSources addObject:str];
// 刷新表格,要在主线程
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self.tableView reloadData];
}];
}
// 监听读取数据
[sock readDataWithTimeout:-1 tag:0];
}
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
{
NSLog(@"与服务器端口连接 %@",err);
}
#pragma mark - <UITableViewDataSource>
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.dataSources.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *ID = @"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
cell.textLabel.text = self.dataSources[indexPath.row];
return cell;
}
@end
客户端演示: