rtmp協(xié)議,是基于tcp的協(xié)議,首先我們需要建立起tcp連接.socket是對tcp協(xié)議的封裝,因此我們用socket來建立起連接.幸運(yùn)的是,蘋果給我們提供了簡單的接口,方便我們使用.
代碼如下:
//.h文件
#import <Foundation/Foundation.h>
typedef NSStreamEvent SGStreamStatus;
@class SGStreamSession;
@protocol SGStreamSessionDelegate <NSObject>
- (void)streamSession:(SGStreamSession *)session didChangeStatus:(SGStreamStatus)streamStatus;
@end
@interface SGStreamSession : NSObject
@property (nonatomic,assign,readonly) SGStreamStatus streamStatus;
@property (nonatomic,weak) id<SGStreamSessionDelegate> delegate;
//連接到服務(wù)器
- (void)connectToServer:(NSString *)host port:(UInt32)port;
//斷開連接
- (void)disConnect;
//讀取數(shù)據(jù)
- (NSData *)readData;
//寫數(shù)據(jù)
- (NSInteger)writeData:(NSData *)data;
@end
//.m文件
#import "SGStreamSession.h"
#define SGLog NSLog
@interface SGStreamSession()<NSStreamDelegate>
{
NSInputStream *_inputStream;
NSOutputStream *_outputStream;
}
@end
@implementation SGStreamSession
- (instancetype)init{
if (self = [super init]) {
_streamStatus = NSStreamEventNone;
}
return self;
}
- (void)connectToServer:(NSString *)host port:(UInt32)port;{
if (self.streamStatus > 0) {
[self close];
}
//輸入流,讀取數(shù)據(jù)
CFReadStreamRef readStream;
//輸出流,負(fù)責(zé)寫數(shù)據(jù)
CFWriteStreamRef writeStream;
//rtmp協(xié)議默認(rèn)端口為1935
if (port <= 0) {
port = 1935;
}
//建立連接
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)host, port, &readStream, &writeStream);
//注意_bridge_transfer,轉(zhuǎn)移內(nèi)存管理所有權(quán)
_inputStream = (__bridge_transfer NSInputStream *)readStream;
_outputStream = (__bridge_transfer NSOutputStream *)writeStream;
_outputStream.delegate = self;
_inputStream.delegate = self;
[_outputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[_inputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
//打開輸入流和輸出流
[_inputStream open];
[_outputStream open];
}
#pragma mark -------delegate---------
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {
switch (eventCode) {
case NSStreamEventNone: {
return;//此處是return
}
case NSStreamEventOpenCompleted: {
if (_inputStream == aStream ) {
SGLog(@"連接成功");
_streamStatus = NSStreamEventOpenCompleted;
}
break;
}
case NSStreamEventHasBytesAvailable: {
SGLog(@"有字節(jié)可讀");
_streamStatus |= NSStreamEventHasBytesAvailable;
break;
}
case NSStreamEventHasSpaceAvailable: {
SGLog(@"可以發(fā)送字節(jié)");
_streamStatus |= NSStreamEventHasSpaceAvailable;
break;
}
case NSStreamEventErrorOccurred: {
SGLog(@"連接出現(xiàn)錯誤");
_streamStatus = NSStreamEventErrorOccurred;
break;
}
case NSStreamEventEndEncountered: {
SGLog(@"連接結(jié)束");
_streamStatus = NSStreamEventEndEncountered;
break;
}
}
if ([self.delegate respondsToSelector:@selector(streamSession:didChangeStatus:)]) {
[self.delegate streamSession:self didChangeStatus:_streamStatus];
}
}
- (void)disConnect{
[self close];
}
- (void)close{
[_inputStream close];
[_outputStream close];
[_inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[_outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
_streamStatus = NSStreamEventNone;
_outputStream = nil;
_inputStream = nil;
_inputStream.delegate = nil;
_outputStream.delegate = nil;
}
- (void)dealloc{
NSLog(@"%s",__func__);
[self close];
}
- (NSData *)readData{
uint8_t buff[4096];//最大支持4K
NSUInteger len = [_inputStream read:buff maxLength:sizeof(buff)];
NSData *data = nil;
if(len < sizeof(buff) && (_streamStatus & NSStreamEventHasBytesAvailable)){
_streamStatus ^= NSStreamEventHasBytesAvailable;
data = [NSData dataWithBytes:buff length:len];
}
return data;
}
- (NSInteger)writeData:(NSData *)data{
if (data.length == 0) {
return 0;
}
NSInteger ret = 0;
if (_outputStream.hasSpaceAvailable) {
ret = [_outputStream write:data.bytes maxLength:data.length];
}
if (ret > 0 && (_streamStatus & NSStreamEventHasSpaceAvailable)) {
//移除標(biāo)志位
_streamStatus ^= NSStreamEventHasSpaceAvailable;
}
return ret;
}
@end
注釋已經(jīng)寫得很詳細(xì)了.這里提醒一下,里面的狀態(tài)處理如果看不懂,不要糾結(jié),|= 和 ^= 可以認(rèn)為是 = .如果想深入了解,可以看看位枚舉.