(原創(chuàng), 請勿轉(zhuǎn)載)
有好多童鞋面對socket大有無從下手之感, ?我就隨便說說
socket 翻譯過來叫套接字, 你可以理解他為長連接, 所謂長連接, 就讓你的服務(wù)器與手機(jī)端保持著連續(xù)性的聯(lián)系(心跳), 從而實現(xiàn)手機(jī)端實時接收數(shù)據(jù)?
我在群里看到有的童鞋討論socket時, 在網(wǎng)上找到的文章都是學(xué)術(shù)性太強(qiáng)(其實就是懶得看的借口), ?就想找一個告訴我該怎么做就完了, ?現(xiàn)在我寫這個就告訴你該怎么做, 至于原理, 自己查去吧~~~網(wǎng)上有的是
socket 有自己的一套函數(shù)庫,? 他有他自己的一堆函數(shù), 只不過用著很難受, 現(xiàn)在有個大神跳出來,? 把socket封裝的又好又棒, 方便簡潔, 簡單易用, 為什么不用呢?
GCDAsyncSocket
GCDAsyncUdpSocket
這兩個類封裝的非常好, 我今天就簡單的講一下怎么新建個socket, 怎么發(fā)數(shù)據(jù)接數(shù)據(jù)就完了,?
第一步, 新建個工程
第二步, 導(dǎo)入一個包, CFNetwork.framework, 導(dǎo)入GCDAsyncSocket.h? GCDAsyncSocket.m? GCDAsyncUdpSocket.h? ? GCDAsyncUdpSocket.m 這4個文件, Demo鏈接在下邊, 里面有這些文件
第三步, 新建個單例 開始上代碼了
+ (Singleton *)sharedInstance{
? ? ? static Singleton *singleton = nil;
? ? ? static dispatch_once_t oneToken;
? ? ? dispatch_once(&oneToken, ^{
? ? ? ?singleton = [[Singleton alloc]init];
? ? ? });
? ? ? ?return singleton;
}
import類 ? 并聲明屬性與方法 ?還有協(xié)議GCDAsyncSocketDelegate
#import "GCDAsyncSocket.h"
#import "GCDAsyncUdpSocket.h"
///socket對象
@property (nonatomic, strong)GCDAsyncSocket *socket;
//主機(jī)
@property (nonatomic, copy)NSString *socketHost;
//端口
@property (nonatomic, assign)UInt16 socketPort;
///向服務(wù)器發(fā)送的數(shù)據(jù)
@property (nonatomic, copy)NSString *sendData;
///心跳 計時器
@property (nonatomic, retain) NSTimer *connectTimer;
- (void)socketConnectHost;// socket啟動連接
- (void)cutOffSocket; // 斷開socket連接
///服務(wù)器反饋回調(diào)
- (void)readData:(void(^)(NSData *data))block;
方法一 : socket啟動連接
-(void)socketConnectHost{
dispatch_queue_t queue;
self.socket = [[GCDAsyncSocket alloc]initWithSocketQueue:queue];
NSError *error = nil;
[self.socket connectToHost:self.socketHost onPort:self.socketPort withTimeout:3 error:&error];
}
方法二 :? 斷開socket連接
// 切斷socket
-(void)cutOffSocket{
[self.connectTimer invalidate];
[self.socket disconnect];
}
接下來是幾個有用的代理的介紹
#pragma mark? -GCDAsyncSocketDelegate 代理 連接成功回調(diào)
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port;
#pragma mark? -GCDAsyncSocketDelegate 代理 斷線回調(diào)
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(nullable NSError *)err;
#pragma mark? -GCDAsyncSocketDelegate 代理 服務(wù)器反饋回調(diào)
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag;
具體實現(xiàn)看下邊
// 心跳方法
-(void)longConnectToSocket{
//每個心跳向服務(wù)器發(fā)送的數(shù)據(jù)
NSData *dataStream? = [self.sendData.copy dataUsingEncoding:NSUTF8StringEncoding];
[self.socket writeData:dataStream withTimeout:1 tag:1];
}
#pragma mark? -GCDAsyncSocketDelegate 代理 連接成功回調(diào)
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port{
NSLog(@"socket連接成功");
// 每隔30s像服務(wù)器發(fā)送心跳包
self.connectTimer = [NSTimer scheduledTimerWithTimeInterval:30 target:self selector:@selector(longConnectToSocket) userInfo:nil repeats:YES];// 在longConnectToSocket方法中進(jìn)行長連接需要向服務(wù)器發(fā)送的訊息
[self.connectTimer fire];
}
#pragma mark? -GCDAsyncSocketDelegate 代理 斷線回調(diào)
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(nullable NSError *)err{
// 判斷是不是掉線栋烤,是服務(wù)器掉線還是用戶手動鏈接, 要是掉線就重連
//? ? [self socketConnectHost];
}
#pragma mark? -GCDAsyncSocketDelegate 代理 服務(wù)器反饋回調(diào)
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{
ReadBlock(data);
}
在聲明個block做服務(wù)器回調(diào)
{
void (^ReadBlock)(NSData *data);
}
- (void)readData:(void(^)(NSData *data))block{
ReadBlock = block;
}
單例的具體使用
[Singleton sharedInstance].socketHost = @"192.186.111.11";// host設(shè)定
[Singleton sharedInstance].socketPort = 10086;// port設(shè)定
///你心跳發(fā)送給服務(wù)器的數(shù)據(jù), 可以即時修改
[Singleton sharedInstance].sendData = @"我要鐵馬長戈腰帶";
// 在連接前一定先進(jìn)行斷開, 如果對一個正處于連接狀態(tài)的socket進(jìn)行連接,會崩潰
[[Singleton sharedInstance] cutOffSocket];
[[Singleton sharedInstance] socketConnectHost];
//服務(wù)器回調(diào)反饋
[[Singleton sharedInstance] readData:^(NSData *data) {
}];
Demo鏈接
https://pan.baidu.com/s/1bppaZ19
mkrw
參考文章: https://my.oschina.net/joanfen/blog/287238