前言
最近在做一套点对点传输的软件, 需要用到Socket进行设备间通讯. 去网上查了查, 对Socket分装比较好的就是目前特别火的GCDAsyncSocket这个类了, 这篇文章就GDCAsyncSocket与GCDAsyncUdpSocket进行单例封装, 一台设备通过UDP广播, 对外发送自己的IP地址与端口号, 另一台设备做接收, 接收后连接到IP地址与端口号, 从而进行TCP连接进行数据传输. 说明一下, SocketHelper单例类是Server与Client两用的, 使用时需指定设备类型. 下面先来看一下SocketHelper.
SocketHelper.h
#import <Foundation/Foundation.h>
#import <arpa/inet.h>
#import <ifaddrs.h>
#import "GCDAsyncSocket.h"
#import "GCDAsyncUdpSocket.h"
#define TAG 999 // 用于设备间通信
#define BROADCAST_HOST @"255.255.255.255"
#define CLIENT_UDP_PORT 7890
#define TCP_PORT 45000
#define kDATACONVERSION @"Dictionary To Data"
typedef enum : NSUInteger {
Server,
Client,
} Type;
@interface SocketHelper : NSObject <GCDAsyncSocketDelegate, GCDAsyncUdpSocketDelegate> {
dispatch_queue_t _tcpSocketQueue;
dispatch_queue_t _udpSocketQueue;
dispatch_source_t _source; // 定时起源
}
@property (nonatomic, strong) GCDAsyncSocket *tcpSocket; // Server | Client 进行TCP连接使用
@property (nonatomic, strong) GCDAsyncUdpSocket *udpSocket; // Server 通过广播向 Client 发送 Server 的IP地址
@property (nonatomic, strong, readonly) NSMutableArray *connectedSocekts; // 存放已连接 Socket 的数组
@property (nonatomic, strong, readonly) NSDictionary *readUdpDataDic; // @{host:@(port)}
@property (nonatomic, assign) long tag; // 对数据进行区分
@property (nonatomic, assign, readonly) BOOL isListening; // Server 开始监听 Client
@property (nonatomic, assign) Type type;
@property (nonatomic, copy) NSString *tcpHost;
@property (nonatomic, assign) UInt16 tcpPort;
@property (nonatomic, copy) NSString *udpHost;
@property (nonatomic, assign) UInt16 udpPort;
#pragma mark - SHARED HELPER
+ (SocketHelper *)sharedHelper;
#pragma mark - BROADCAST
/**
* 允许 Socket 发送广播
* @param flag YES or NO
* @reutrn YES or NO
*/
- (BOOL)enableBroadcast:(BOOL)flag;
#pragma mark - BING
/**
* 绑定 UDP Socket 的端口
* @param port 端口号
* @reutrn YES or NO
*/
- (BOOL)bindToPort:(uint16_t)port;
#pragma mark - RECEIVING
/**
* 成功开启后可连续接收数据
* @return YES or NO
*/
- (BOOL)beginReceiving;
/**
* 成功开启后只接收一次数据, 开在之后添加 - (BOOL)beginingReceiving 做转换
*/
- (BOOL)receiveOnce;
#pragma mark - UDP CONNECT
/**
* 通过广播对外发送数据
* @param data 广播的数据
* @param host 向 host 所在的地址进行广播 @"255.255.255.255"
* @param port 广播的端口号, 填写 Client 绑定的端口
*/
- (void)broadcastData:(NSData *)data toHost:(NSString *)host port:(uint16_t)port withTag:(long)tag;
/**
* 开始进行广播
*/
- (void)startedBroadcasting;
/**
* 开始循环发送广播数据
*/
- (void)startCycle;
#pragma mark - UDP DATA PRPGRESSING
/**
* 向指定 host:port 发送数据
* @param data 发送的数据
* @param host 指定的 IP 地址
* @param port 指定端口
* @param tag 通过 tag 的值对传输数据进行分类
*/
- (void)sendData:(NSData *)data toHost:(NSString *)host port:(uint16_t)port withTag:(long)tag;
#pragma mark - TCP CONNECT
/**
* Server 对指定端口进行监听
*/
- (void)startListeningPort;
/**
* Client 通过 Host:Port 与 Server 进行连接
*/
- (void)startConnect;
#pragma mark - TCP DATA PRPGRESSING
/**
* TCP 连接时发送数据
* @param data 需要传送的数据
* @param tag 通过 tag 的值对传输数据进行分类
*/
- (void)writeData:(NSData *)data withTag:(long)tag;
#pragma mark - GET IP ADDRESS
/**
* 获取本机的IP地址
@return IP地址的字符串
*/
- (NSString *)getIpAddress;
#pragma mark - DATA PRPGRESSING
/**
* 将