zl程序教程

您现在的位置是:首页 >  移动开发

当前栏目

iOS 使用第三方库CocoaAsyncSocket进行Tcp通讯

iosTCP 进行 第三方 通讯 使用
2023-09-11 14:22:56 时间

iPhone的标准推荐CFNetwork C库编程。但是编程比较烦躁。在其它OS往往用类来封装的对Socket函数的处理。比如MFC的CAsysncSocket.在iphone也有类似于开源项目.cocoa AsyncSocket库, 官方网站: http://code.google.com/p/cocoaasyncsocket/ 它用来简化CFnetwork的调用.。

但是由于中国的长城防火墙,谷歌网站无法访问。因此,这里我是从github上下的 https://github.com/robbiehanson/CocoaAsyncSocket

AsyncSocket分为2个版本(个人理解如下)

(1)GCD版。Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。 简单的说就是基于多线程。

(2)RunLoop版。就是单线程以阻塞处理事件而形成一个消息循环,执行完毕后并不退出。

目录结构如下


AsyncSocket包括TCP和UDP,通过实现委托AsyncSocketDelegate进行交互。

调用此API时需先引入CFNetWork.framework。(网上有的说需要加入该框架,但是为在 iOS9 XCode7beta 中不添加亦可正常运行)

如果是实现GCD版本,则需要将GCD文件夹中的4个文件加入项目


这里只实现GCD版本的Tcp,Udp类似,实现代码如下

1、Main.storyboard


2、ConnectionDef

//
//  ConnectDef.h
//  AsyncSocketDemo
//
//  Created by 555chy on 6/22/16.
//  Copyright © 2016 555chy. All rights reserved.
//

#ifndef ConnectDef_h
#define ConnectDef_h

#define DEF_STR_ENCODING    NSUTF8StringEncoding
//连接超时时间为60秒
#define CONNECT_TIMEOUT     60
#define READ_TIMEOUT        -1
//发送数据超时时间为60秒
#define WRITE_TIMEOUT       60

#define SERVER_QUEUE        "tcpServerQueue"
#define CLIENT_QUEUE        "tcpClientQueue"

#define SERVER_ADDRESS      @"127.0.0.1"
#define SERVER_PORT         12345

#endif /* ConnectDef_h */

2、TcpServer.h

//
//  TcpServer.h
//  AsyncSocketDemo
//
//  Created by 555chy on 6/21/16.
//  Copyright © 2016 555chy. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "GCDAsyncSocket.h"
#import "ConnectionDef.h"

@interface TcpServer : NSObject  <GCDAsyncSocketDelegate> {
    GCDAsyncSocket *serverSocket;
    NSMutableArray *clientArray;
    long readTag;
    long writeTag;
}

-(long)getReadTag;
-(long)getWriteTag;
-(void)createTcpSocket:(const char *)queueName acceptOnPort:(uint16_t)port;
-(void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket;
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag;
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag;
-(void)socket:(GCDAsyncSocket *)sock writeString:(NSString *)str withTag:(long)tag;
-(void)broadcastStr:(NSString *)str;
-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err;

@end

3、TcpServer.m

//
//  TcpServer.m
//  AsyncSocketDemo
//
//  Created by 555chy on 6/21/16.
//  Copyright © 2016 555chy. All rights reserved.
//

#import "TcpServer.h"

@implementation TcpServer

-(long)getReadTag {
    return readTag++;
}

-(long)getWriteTag {
    return writeTag++;
}

-(void)createTcpSocket:(const char *)queueName acceptOnPort:(uint16_t)port {
    clientArray = [NSMutableArray array];
    dispatch_queue_t dispatchQueue = dispatch_queue_create(queueName, NULL);
    serverSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatchQueue];
    [serverSocket acceptOnPort:port error:nil];
    readTag = 0;
    writeTag = 0;
}

-(void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket {
    NSString* ip = [newSocket connectedHost];
    uint16_t port = [newSocket connectedPort];
    NSLog(@"server didAcceptNewSocket [%@:%d]", ip, port);
    [clientArray addObject:newSocket];
    //一直等待readSocket的消息(tag是一个标记类似于tcp数据包中的序列号)
    [newSocket readDataWithTimeout:READ_TIMEOUT tag:[self getReadTag]];
}

-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
    NSString *ip = [sock connectedHost];
    uint16_t port = [sock connectedPort];
    NSString *str = [[NSString alloc] initWithData:data encoding:DEF_STR_ENCODING];
    NSLog(@"server didReadData [%@:%d] %@", ip, port, str);
    //再次接收数据,因为这个方法只接收一次
    [sock readDataWithTimeout:READ_TIMEOUT tag:[self getReadTag]];
}

-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag {
    NSString *ip = [sock connectedHost];
    uint16_t port = [sock connectedPort];
    NSLog(@"server didWriteDataWithTag [%@:%d]", ip, port);
}

-(void)socket:(GCDAsyncSocket *)sock writeString:(NSString *)str withTag:(long)tag {
    NSData *data = [str dataUsingEncoding:DEF_STR_ENCODING];
    [sock writeData:data withTimeout:WRITE_TIMEOUT tag:[self getWriteTag]];
}

-(void)broadcastStr:(NSString *)str {
    for(GCDAsyncSocket *sock in clientArray) {
        [self socket:sock writeString:str withTag:[self getWriteTag]];
    }
}

-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {
    NSString *ip = [sock connectedHost];
    uint16_t port = [sock connectedPort];
    NSLog(@"server socketDidDisconnect [%@:%d]", ip, port);
    [clientArray removeObject:sock];
}

@end

4、TcpClient.h

//
//  TcpClient.h
//  AsyncSocketDemo
//
//  Created by 555chy on 6/21/16.
//  Copyright © 2016 555chy. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "GCDAsyncSocket.h"
#import "ConnectionDef.h"

@interface TcpClient : NSObject<GCDAsyncSocketDelegate> {
    GCDAsyncSocket *clientSocket;
    long readTag;
    long writeTag;
}

-(long)getReadTag;
-(long)getWriteTag;
-(void)createTcpSocket:(const char *)queueName connectToHost:(NSString *) host onPort:(uint16_t)port;
-(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port;
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag;
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag;
-(void)writeString:(NSString *)str withTag:(long)tag;
-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err;

@end

5、TcpClient.m

//
//  TcpClient.m
//  AsyncSocketDemo
//
//  Created by 555chy on 6/21/16.
//  Copyright © 2016 555chy. All rights reserved.
//

#import "TcpClient.h"

@implementation TcpClient

-(long)getReadTag {
    return readTag++;
}

-(long)getWriteTag {
    return writeTag++;
}

-(void)createTcpSocket:(const char *)queueName connectToHost:(NSString *) host onPort:(uint16_t)port {
    dispatch_queue_t dispatchQueue = dispatch_queue_create(queueName, NULL);
    clientSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatchQueue];
    [clientSocket connectToHost:host onPort:port withTimeout:CONNECT_TIMEOUT  error:nil];
}

-(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port {
    NSLog(@"client didConnectToHost [%@:%d]", host, port);
    [sock readDataWithTimeout:READ_TIMEOUT tag:[self getReadTag]];
}

-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
    NSString *ip = [sock connectedHost];
    uint16_t port = [sock connectedPort];
    NSString *str = [[NSString alloc] initWithData:data encoding:DEF_STR_ENCODING];
    NSLog(@"client didReadData [%@:%d] %@", ip, port, str);
}

-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag {
    NSString *ip = [sock connectedHost];
    uint16_t port = [sock connectedPort];
    NSLog(@"client didWriteDataWithTag [%@:%d]", ip, port);

}

-(void)writeString:(NSString *)str withTag:(long)tag {
    NSData *data = [str dataUsingEncoding:DEF_STR_ENCODING];
    [clientSocket writeData:data withTimeout:WRITE_TIMEOUT tag:[self getWriteTag]];
}

-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {
    NSString *ip = [sock connectedHost];
    uint16_t port = [sock connectedPort];
    NSLog(@"client socketDidDisconnect [%@:%d]", ip, port);
    //可以在这边实现断线重连机制
}

@end

7、ViewController.h

//
//  ViewController.h
//  AsyncSocketDemo
//
//  Created by 555chy on 6/21/16.
//  Copyright © 2016 555chy. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "TcpServer.h"
#import "TcpClient.h"
#import "ConnectionDef.h"

@interface ViewController : UIViewController 

@property (nonatomic, retain) TcpServer *tcpServer;
@property (nonatomic, retain) TcpClient *tcpClient;

@property (weak, nonatomic) IBOutlet UITextField *serverSendTextField;
@property (strong, nonatomic) IBOutlet UIView *serverSendButton;
@property (weak, nonatomic) IBOutlet UITextField *clientSendTextField;
@property (weak, nonatomic) IBOutlet UIButton *clientSendButton;
- (IBAction)serverSendButtonClick:(id)sender;
- (IBAction)clientSendButtonClick:(id)sender;

@end

8、ViewController.m

//
//  ViewController.m
//  AsyncSocketDemo
//
//  Created by 555chy on 6/21/16.
//  Copyright © 2016 555chy. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    _tcpServer = [[TcpServer alloc] init];
    _tcpClient = [[TcpClient alloc] init];
    [_tcpServer createTcpSocket:SERVER_QUEUE acceptOnPort:SERVER_PORT];
    [_tcpClient createTcpSocket:CLIENT_QUEUE connectToHost:SERVER_ADDRESS onPort:SERVER_PORT];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (IBAction)serverSendButtonClick:(id)sender {
    [_tcpServer broadcastStr:_serverSendTextField.text];
}

- (IBAction)clientSendButtonClick:(id)sender {
    [_tcpClient writeString:_clientSendTextField.text withTag:[_tcpClient getWriteTag]];
}

@end

实际效果图如下