Soket转发消息服务(群聊)

编写群聊服务端代码,稍加改写之前的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
客户端演示:





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
public class Myconnection { /// <summary> /// 连接套接字 /// </summary> Socket _client = null; /// <summary> /// 信息展示 /// </summary> ShowMgs _showMgs = null; /// <summary> /// 关闭通信通道 /// </summary> ShutDown _shutDown = null; /// <summary> /// 无参构造函数 /// </summary> public Myconnection() { } bool _working = true; /// <summary> /// 带参构造函数 /// </summary> /// <param name="client"></param> /// <param name="shoeMgs"></param> /// <param name="shutMgs"></param> public Myconnection(Socket client, ShowMgs showMgs, ShutDown shutMgs) { this._client = client; this._showMgs = showMgs; this._shutDown = shutMgs; //创建线程去监听客户端 Thread thread = new Thread(Accept); thread.IsBackground = true; thread.Start(); } public void Accept() { try { //监听客户端信息 while (_working) { //创建缓存区 byte[] _byte = new byte[1024 * 1024 * 1]; //接收客户端信息并保存到缓存区 int _length = _client.Receive(_byte); //将数组转换成服务器 string str = Encoding.Default.GetString(_byte, 0, _length); _showMgs(str); } } catch (Exception ex) { _showMgs(ex.Message); _client.Shutdown(SocketShutdown.Both); _client.Disconnect(false); _client = null; } } /// <summary> /// 发送文本信息 /// </summary> /// <param name="str"></param> public void SendText(string str) { //将字符串转换成数组 byte[] _byte = Encoding.Default.GetBytes(str); _client.Send(_byte); } /// <summary> /// 关闭通信通道 /// </summary> public void Close() { _client.Shutdown(SocketShutdown.Both); _client.Close(); _client.Disconnect(true); _client = null; } }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值