服務(wù)端Socket-CocoaAsyncSocket建立連接&發(fā)送數(shù)據(jù) - (Obj-C)

使用CocoaAsyncSocket先來模擬創(chuàng)建一個服務(wù)端(創(chuàng)建一個Mac工程):

UI搭建.png

具體步驟:
1.創(chuàng)建一個用于監(jiān)聽的Socket
2.綁定ip&監(jiān)聽端口&接受新連接
3.監(jiān)聽新的連接
4.接收數(shù)據(jù)/發(fā)送數(shù)據(jù)

示例代碼:

#import "ViewController.h"
#import "GCDAsyncSocket.h"

@interface ViewController () <GCDAsyncSocketDelegate>

// 1. 用于監(jiān)聽的socket
@property (nonatomic,strong) GCDAsyncSocket *listenSocket;
// 用于存放數(shù)據(jù)交互的socket
@property (nonatomic,strong) NSMutableArray *connectedSockets;

@end

@implementation ViewController

// 點擊開始服務(wù)器按鈕

- (IBAction)clickStartServerButton:(id)sender {
    
    // 2. 綁定ip&監(jiān)聽端口&接受新連接封裝在一個方法中
    /*
       參數(shù)1: 地址
       參數(shù)2: 端口
       參數(shù)3: 錯誤
    */
    BOOL success = [self.listenSocket acceptOnInterface:@"127.0.0.1" port:1234 error:nil];
    
    if (success) {
        NSLog(@"服務(wù)器開啟成功");
    } else {
        NSLog(@"服務(wù)器開啟失敗");
    }
    
}

- (void)viewDidLoad {
    [super viewDidLoad];

}
- (void)setRepresentedObject:(id)representedObject {
    [super setRepresentedObject:representedObject];
    
}

#pragma mark --  GCDAsyncSocketDelegate


/**
 *  3. 已經(jīng)接受到新的連接后調(diào)用
 *
 *  @param sock      服務(wù)端用于監(jiān)聽的socket
 *  @param newSocket 服務(wù)端用于數(shù)據(jù)交互的socket (Socket是一個調(diào)用接口,不能被傳遞的)
 */
- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket{
    
    /**
     * Called when a socket accepts a connection.
     * Another socket is automatically spawned to handle it.
     *
     * You must retain the newSocket if you wish to handle the connection.
     * Otherwise the newSocket instance will be released and the spawned connection will be closed.
     
--->  如果不強引用用于數(shù)據(jù)交互的socket,當(dāng)連接后服務(wù)器就會把連接關(guān)閉了
     e.g. 終端中通過telnet指令連接服務(wù)器:    telnet 127.0.0.1 1234
          終端提示:  Trying 127.0.0.1...
                    Connected to localhost.
                    Escape character is '^]'.
                    Connection closed by foreign host.
      一旦有新的連接就會調(diào)用這個方法,所以每一個連接都需要強引用負(fù)責(zé)數(shù)據(jù)交互的socket
     
     *
     * By default the new socket will have the same delegate and delegateQueue.
     * You may, of course, change this at any time.
     **/
    
    [self.connectedSockets addObject:newSocket]; // 添加到可變數(shù)據(jù),進行強引用
    
    // newSocket.connectedHost 連接的端口號,可以打印出連接這臺服務(wù)器的主機ip
    NSLog(@"接收到來自%@的連接",newSocket.connectedHost);
    
    // 數(shù)據(jù)交互操作一定要使用newSocket,使用服務(wù)端用于監(jiān)聽的socket將會接收發(fā)送失敗
    
    // 4.1 發(fā)送數(shù)據(jù)
    NSString *string = [NSString stringWithFormat:@"歡迎連接我的服務(wù)器~"];
    
    // withTimeout 超時時間,設(shè)置-1代表永遠不超時
    // tag 類似于button的tag值
    [newSocket writeData:[string dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:0];
    
    // 接收數(shù)據(jù)  (只能接收一次)
    [newSocket readDataWithTimeout:-1 tag:0];
    
    // 4.2 接收數(shù)據(jù)  定時器 輪循,一直來接收數(shù)據(jù)
    // [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(readData:) userInfo:newSocket repeats:YES];
    
    // 子線程的消息循環(huán)默認(rèn)不會開啟,需要手動開啟
    // [[NSRunLoop currentRunLoop] run];
    
    //定時器的方式接收數(shù)據(jù)缺點:1s執(zhí)行一次,并不實時,受設(shè)置的計時約束,另外如果沒有新數(shù)據(jù)也在調(diào)用
}


// 發(fā)送數(shù)據(jù)
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag{
    
    NSLog(@"已經(jīng)發(fā)送數(shù)據(jù)后調(diào)用");
    
}
/**
 *  已經(jīng)接收到數(shù)據(jù)后調(diào)用
 *
 *  @param sock 數(shù)據(jù)交互的socket
 *  @param data 接收到的數(shù)據(jù)
 *  @param tag  標(biāo)記
 */
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{
    
    
    NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
    
    // 4.2 接收數(shù)據(jù)  (按需獲取)
    [sock readDataWithTimeout:-1 tag:0];
}



// 定時器調(diào)用的方法
- (void)readData:(NSTimer *)timer{
    
    // 接收數(shù)據(jù)
    [timer.userInfo readDataWithTimeout:-1 tag:0];
    
}
#pragma mark -- 懶加載

// 用于監(jiān)聽的socket
- (GCDAsyncSocket *)listenSocket{
    
    if (_listenSocket == nil) {
        
        /*
         delegateQueue:時效性選擇主線程,性能更好選擇異步線程
         socketQueue:  執(zhí)行連接,接受再去隊列中執(zhí)行,設(shè)置NULL會自動設(shè)置隊列,使用自己的隊列容易出現(xiàn)線程問題
         */
        
        _listenSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(0, 0) socketQueue:NULL];
        
    }
    return _listenSocket;
}

// 用于存放數(shù)據(jù)交互的socket
- (NSMutableArray *)connectedSockets{
    
    if (_connectedSockets == nil) {
        _connectedSockets = [NSMutableArray array];
    }
    return _connectedSockets;
}


@end

實時接收數(shù)據(jù):

2016-07-26 13:39:01.487 01-服務(wù)端Socket[8522:196543] 服務(wù)器開啟成功
2016-07-26 13:39:13.944 01-服務(wù)端Socket[8522:196605] 接收到來自127.0.0.1的連接
2016-07-26 13:39:13.945 01-服務(wù)端Socket[8522:196598] 已經(jīng)發(fā)送數(shù)據(jù)后調(diào)用
2016-07-26 13:39:16.328 01-服務(wù)端Socket[8522:196768] test
2016-07-26 13:39:19.079 01-服務(wù)端Socket[8522:196768] test
2016-07-26 13:39:20.967 01-服務(wù)端Socket[8522:196598] test
終端.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容