iOS Socket(4) —— CocoaAsyncSocket的使用

CocoaAsyncSocket

CocoaAsyncSocket是一個異步Socket的框架,支持TCP和UDP,GCDAsyncSocket類對應的是TCP,GCDAsyncUdpSocket類對應的是UDP。git

TCP客戶端的實現

#import "ViewController.h"
#import "GCDAsyncSocket.h"
#include <netinet/in.h>
#import <arpa/inet.h>
#import <ifaddrs.h>
@interface ViewController ()<GCDAsyncSocketDelegate>
{
   GCDAsyncSocket *_clientSocket;
   NSString *_loc_ipAdr,*_loc_port,*_des_ipAdress,*_des_port;

}

@property (weak, nonatomic) IBOutlet UITextView *recvTextView;
@property (weak, nonatomic) IBOutlet UITextField *sendTF;


@end

@implementation ViewController

- (void)viewDidLoad {
   [super viewDidLoad];
   _loc_ipAdr = [self getIPAddress];
   _loc_port = @"10001";
   
   _des_ipAdress = @"127.0.0.1";
   _des_port = @"10000";
   
   //建立socket
   _clientSocket = [[GCDAsyncSocket alloc]initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
   //鏈接服務器
   NSError *error;
   [_clientSocket connectToHost:_des_ipAdress onPort:_des_port.integerValue error:&error];
   if (error) {
       NSLog(@"socket 鏈接失敗");
   }
   
   
   // Do any additional setup after loading the view, typically from a nib.
}


#pragma mark - GCDAsyncSocketDelegate

// 鏈接成功
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port {
   NSLog(@"socket 鏈接成功");
   // 讀取數據,必須添加,至關於主動添加一個讀取請求,否則不會執行讀取信息回調方法
   [_clientSocket readDataWithTimeout:-1 tag:0];
  
}

// 已經斷開連接
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {
   
   NSLog(@"socket 斷開鏈接");
}

//讀取到數據
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
   
   // 注意:要想長鏈接,必須還要在 DidReceiveData 的 delegate 中再寫一次 [_udpSocket receiveOnce:&error]
   // 讀取數據,讀取完信息後,從新向隊列中添加一個讀取請求,否則當收到信息後不會執行讀取回調方法。
   [_clientSocket readDataWithTimeout:-1 tag:0];
   
   NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
   self.recvTextView.text = [NSString stringWithFormat:@"收到消息:%@",str];
}


//發送消息
- (IBAction)send:(id)sender {
   
  [_clientSocket writeData:[self.sendTF.text dataUsingEncoding:NSUTF8StringEncoding] withTimeout:30 tag:0];
}

#pragma mark - 獲取本地 IP 地址

- (NSString *)getIPAddress {
   
   NSString *address = @"error";
   struct ifaddrs *interfaces = NULL;
   struct ifaddrs *temp_addr = NULL;
   int success = 0;
   
   // retrieve the current interfaces - returns 0 on success
   success = getifaddrs(&interfaces);
   
   if (success == 0) {
       
       // Loop through linked list of interfaces
       temp_addr = interfaces;
       
       while (temp_addr != NULL) {
           
           if (temp_addr->ifa_addr->sa_family == AF_INET) {
               
               // Check if interface is en0 which is the wifi connection on the iPhone
               if ([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) {
                   
                   // Get NSString from C String
                   address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];
               }
           }
           temp_addr = temp_addr->ifa_next;
       }
   }
   
   // Free memory
   freeifaddrs(interfaces);
   return address;
}

複製代碼

TCP服務端的實現

@interface ViewController ()<GCDAsyncSocketDelegate>
{
    NSString *_loc_ipAdr,*_loc_port,*_des_ipAdress,*_des_port;
    GCDAsyncSocket *_serviceSocket,*_clientSocket;
}

@property (weak) IBOutlet NSTextField *sendTF;
@property (unsafe_unretained) IBOutlet NSTextView *recvTextView;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    _loc_ipAdr = [self getIPAddress];
    _loc_port = @"10001";
    
    _des_ipAdress = @"127.0.0.1";
    _des_port = @"10000";

    
    //建立socket
    _serviceSocket = [[GCDAsyncSocket alloc]initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
    //監聽
    NSError *error = nil;
    [_serviceSocket acceptOnPort:_des_port.integerValue error:&error];
    if (error != nil) {
        NSLog(@"監聽出錯:%@", error);
    } else{
        NSLog(@"正在監聽...");
    }
    
    // Do any additional setup after loading the view.
}



// 接收到客戶端的鏈接請求
- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket {
    
    // 讀取數據,必須添加,至關於主動添加一個讀取請求,否則不會執行讀取信息回調方法
    [newSocket readDataWithTimeout:-1 tag:0];
    NSLog(@"收到客戶端鏈接....");
    //獲取客戶端的socket
    _clientSocket = newSocket;
}

// 已經斷開連接,協議方法
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {
    
    NSLog(@"socket 斷開鏈接...");
}


//讀取到數據
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
    
    // 注意:要想長鏈接,必須還要在 DidReceiveData 的 delegate 中再寫一次 [_udpSocket receiveOnce:&error]
    // 讀取數據,讀取完信息後,從新向隊列中添加一個讀取請求,否則當收到信息後不會執行讀取回調方法。
    [sock readDataWithTimeout:-1 tag:0];
    
    NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    self.recvTextView.string = [NSString stringWithFormat:@"收到消息:%@",str];
}


- (IBAction)send:(id)sender {
    [_clientSocket writeData:[self.sendTF.stringValue dataUsingEncoding:NSUTF8StringEncoding] withTimeout:30 tag:0];

}

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

    // Update the view, if already loaded.
}

- (NSString *)getIPAddress {
    
    NSString *address = @"error";
    struct ifaddrs *interfaces = NULL;
    struct ifaddrs *temp_addr = NULL;
    int success = 0;
    
    // retrieve the current interfaces - returns 0 on success
    success = getifaddrs(&interfaces);
    
    if (success == 0) {
        
        // Loop through linked list of interfaces
        temp_addr = interfaces;
        
        while (temp_addr != NULL) {
            
            if (temp_addr->ifa_addr->sa_family == AF_INET) {
                
                // Check if interface is en0 which is the wifi connection on the iPhone
                if ([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) {
                    
                    // Get NSString from C String
                    address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];
                }
            }
            temp_addr = temp_addr->ifa_next;
        }
    }
    
    // Free memory
    freeifaddrs(interfaces);
    return address;
}
@end

複製代碼

Demo

  • 下載地址:github.com/namesubai/S…
  • 請先編譯服務端ASyncSocketMac項目,再編譯客戶端ASyncSocketiOS項目
  • 效果圖:

image
相關文章
相關標籤/搜索