利用終端模擬群聊功能

前言

  • 在終端中模擬群聊功能,連接 QQ服務(wù)器的終端命令: telnet命令telnet host(IP地址) port(端口號(hào)) 比如 : telnet 192.168.10.1 1688(端口號(hào)是隨便寫的,只要在規(guī)定的范圍中即可,但是也有可能連接失敗,原因是端口號(hào)已經(jīng)被使用了).
    1.telnet命令是連接服務(wù)器上的某個(gè)端口對(duì)應(yīng)的服務(wù)

  • 首先定義一個(gè)方法用于開啟QQ群聊的服務(wù)器


#import <Foundation/Foundation.h>

@interface WGServicerListener : NSObject

/** 定義一個(gè)對(duì)象方法,用于QQ開啟服務(wù)器 */
- (void)startServeSocket;

@end

  • 在main.m函數(shù)開啟群聊服務(wù)器,并且讓服務(wù)器永不停止(除非程序退出)
#import <Foundation/Foundation.h>
#import "GCDAsyncSocket.h"
#import "WGServicerListener.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        // 創(chuàng)建一個(gè)服務(wù)器的監(jiān)聽對(duì)象
        WGServicerListener *serveListener = [[WGServicerListener alloc] init];
        
        // 監(jiān)聽開啟服務(wù)器
        [serveListener startServeSocket];
        
        // 保證服務(wù)器一直開啟
        [[NSRunLoop mainRunLoop] run];
        
    }
    return 0;
}

  • 監(jiān)聽客戶端和服務(wù)器的連接, 以及監(jiān)聽客戶端是否上傳可數(shù)據(jù)

#import "WGServicerListener.h"
#import "GCDAsyncSocket.h"

@interface WGServicerListener () <GCDAsyncSocketDelegate>

/** 服務(wù)器的Socket對(duì)象 */
@property(nonatomic, strong) GCDAsyncSocket *serverSocket;

/** 保存所有客戶端對(duì)象 */
@property(nonatomic, strong) NSMutableArray *clientSockets;

@end

@implementation WGServicerListener

#pragma mark - 懶加載
- (NSMutableArray *)clientSockets
{
    if (!_clientSockets) {
        _clientSockets = [NSMutableArray array];
    }
    return _clientSockets;
}


- (void)startServeSocket {

    // 創(chuàng)建一個(gè)服務(wù)器的Socket對(duì)象
    GCDAsyncSocket *serverSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(0, 0)];
    
    // 綁定并監(jiān)聽serverSocket對(duì)象
    NSError *error = nil;
    [serverSocket acceptOnPort:1886 error:&error];
    
    // 判斷是否開啟QQ服務(wù)器
    if (!error) {
        NSLog(@"QQ服務(wù)器已經(jīng)開啟");
    } else
    {
        NSLog(@"QQ服務(wù)器開啟失敗");
    }
    
    // 保存創(chuàng)建的服務(wù)器Socket對(duì)象
    self.serverSocket = serverSocket;
    
}

/**
 *  只要有客戶端連接服務(wù)器就會(huì)調(diào)用該代理方法. 第一個(gè)Socket表示服務(wù)器的Socket對(duì)象,第二個(gè)是客戶端的Socket對(duì)象
 *  在該方法中的參數(shù)中:serverSocket就是服務(wù)器端的Socket,所以需要定義一個(gè)屬性強(qiáng)引用著它,第二個(gè)參數(shù)是服務(wù)器
 *  端的clientSocket,用于讀取客戶端上傳的數(shù)據(jù).所以需要定義一個(gè)數(shù)組保存它.
 */

- (void)socket:(GCDAsyncSocket *)serverSocket didAcceptNewSocket:(GCDAsyncSocket *)clientSocket
{
    
//    NSLog(@"%@",serverSocket);
//    NSLog(@"%@",clientSocket);
    // 保存和QQ服務(wù)器連接的客戶端
    [self.clientSockets addObject:clientSocket];
    
    // 監(jiān)聽客戶端有沒有上傳數(shù)據(jù)
    /**
     * -1 表示不要超時(shí)
     */
    [clientSocket readDataWithTimeout:-1 tag:0];
    
    NSLog(@"客戶端%ld已經(jīng)連接到服務(wù)器了",self.clientSockets.count);
}

/**
 *   監(jiān)聽客戶端有沒有上傳數(shù)據(jù),只要和服務(wù)器連接的客戶端發(fā)送了消息,那么就一定會(huì)調(diào)用該方法
 *   第一個(gè)參數(shù)是客戶端(因?yàn)楸O(jiān)聽的是客戶端是否發(fā)送消息)
 */
- (void)socket:(GCDAsyncSocket *)clientSocket didReadData:(NSData *)data withTag:(long)tag
{
    // 傳進(jìn)來(lái)的是一個(gè)NSData類型,需要將它轉(zhuǎn)為字符串類型
    NSString *responeStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"%@",responeStr);
    
    // 發(fā)送消息,在發(fā)送消息之前需要判斷當(dāng)前監(jiān)聽的對(duì)象(客戶端)是不是自己,如果是自己那么就不要發(fā)送消息給自己了
    for (GCDAsyncSocket *socket in self.clientSockets) {
        if (socket != clientSocket) {
            
            [socket writeData:data withTimeout:-1 tag:0];
        }
    }

    // 每次發(fā)送完畢消息,都需要監(jiān)聽客戶端是否上傳了信息,如果不監(jiān)聽,永遠(yuǎn)發(fā)送不了下一條消息
    [clientSocket readDataWithTimeout:-1 tag:0];

    
}
@end
  • 下面是模擬QQ群聊,一個(gè)終端代表一個(gè)客戶端.
    消息發(fā)送的過程 : 客戶端--->服務(wù)器--->另一個(gè)客戶端


    Snip20160309_3.png
  • 知識(shí)拓展
    端口號(hào)不一樣的作用是什么: 比如說(shuō)我們?cè)陔娔X上同時(shí)登陸兩個(gè)QQ,當(dāng)QQ1發(fā)送消息給QQ3,首先是QQ1將消息發(fā)送給QQ的服務(wù)器,服務(wù)器再將數(shù)據(jù)轉(zhuǎn)發(fā)給QQ3,但是同時(shí)QQ2也發(fā)送了消息給QQ3,也是首先將消息發(fā)送到QQ服務(wù)器,最后才是轉(zhuǎn)發(fā)給QQ3,但是,如果QQ3想要回復(fù)信息,也同樣是將信息先發(fā)送給服務(wù)器,服務(wù)器就是通過這個(gè)端口號(hào)來(lái)判定信息該發(fā)給誰(shuí).端口號(hào)是系統(tǒng)自己分配的.

// 箭頭表示發(fā)送消息的方向
QQ1(端口號(hào)01)—> QQ服務(wù)器 —> QQ3
QQ2(端口號(hào)02)—> QQ服務(wù)器 —> QQ3
       —>QQ服務(wù)器—> 根據(jù)端口號(hào)01 —> QQ1
       |
  QQ3  恢復(fù)消息
       | 
       —>QQ服務(wù)器—> 根據(jù)端口號(hào)02—>QQ2

發(fā)送消息的原理 : 客戶端的數(shù)據(jù)—>服務(wù)器 —> 發(fā)給好友(轉(zhuǎn)發(fā)的過程)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,993評(píng)論 19 139
  • 名詞延伸 通俗的說(shuō),域名就相當(dāng)于一個(gè)家庭的門牌號(hào)碼,別人通過這個(gè)號(hào)碼可以很容易的找到你。如果把IP地址比作一間房子...
    楊大蝦閱讀 20,646評(píng)論 2 56
  • Teredo 原理概述 http://www.ipv6bbs.cn/thread-144-1-1.html (出處...
    我是葉問小盆友閱讀 2,174評(píng)論 0 1
  • 好的電影不需要?jiǎng)∏椋高^光影就能感受整個(gè)世界。 一開始不明白為什么取名《頤和園》,畢竟電影中出現(xiàn)的不多,過多的裸露...
    雨舟舟閱讀 248評(píng)論 0 0
  • 寒風(fēng)入夢(mèng)鄉(xiāng),我在北歸的路上 冬雪覆蓋,四野白凈有些荒涼 我坐在窗前,看著玻璃中的另一個(gè)我 呼一口氣,白霧在指尖繚繞...
    閑狐兔閱讀 123評(píng)論 0 0