• 使用AsyncSocket实现RTSP协议


      之前Socket一直使用Linux c来实现,优点是很容易掌握socket的通信流程,缺点是过程比较繁琐。

    所以选择了AsyncSocket来实现socket通信。另外实现了RTSP的通信过程,并在play命令之后,

    再次开始一个UDP会话,用于传输数据。

      项目原型是用RTSP+RTP来实现摄像头的实时监控,RTSP使用TCP来实现,RTP使用UDP实现,

    直接上代码吧!

    工程结构截图如下:

    关于怎么在项目中使用AysncSocket,请查看http://www.cnblogs.com/foxmin/archive/2012/03/11/2389734.html

    RTSPClient.h如下:

      1 //
    2 // ViewController.m
    3 // RTSPClient
    4 //
    5 // Created by Fox on 12-3-11.
    6 // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
    7 //
    8
    9 #import "RTSPClient.h"
    10 #import "AsyncSocket.h"
    11 #import "AsyncUdpSocket.h"
    12
    13
    14
    15 #define KENTER @"\r\n"
    16 #define KBLACK @" "
    17 #define MAX_BUF 10240
    18
    19
    20 static NSString* SERVERADDR = @"172.16.108.200";
    21 static const int SERVERPORT = 554;
    22
    23
    24 @interface RTSPClient ()
    25
    26 @end
    27
    28 @implementation RTSPClient
    29
    30 - (void)viewDidLoad
    31 {
    32 [super viewDidLoad];
    33 // Do any additional setup after loading the view, typically from a nib.
    34
    35
    36 socket = [[AsyncSocket alloc] initWithDelegate:self];
    37
    38 [socket connectToHost:@"172.16.108.200" onPort:554 error:nil];
    39 [self getOptions];
    40
    41
    42 }
    43
    44 - (void)viewDidUnload
    45 {
    46 [super viewDidUnload];
    47 // Release any retained subviews of the main view.
    48 }
    49
    50 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
    51 {
    52 return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
    53 }
    54
    55
    56
    57
    58
    59
    60 #pragma mark RTSP Session
    61 /*
    62 *建立连接,返回服务器对OPTIONS请求的响应
    63 */
    64 -(NSMutableString*)getOptions
    65 {
    66
    67 NSMutableString* options = [[NSMutableString alloc] init];
    68
    69 [options appendFormat:@"OPTIONS rtsp://%@:%d/H264 RTSP/1.0%@",SERVERADDR,SERVERPORT,KENTER];
    70 [options appendFormat:@"CSeq: 2%@",KENTER];
    71 [options appendFormat:@"User-Agent: LibVLC/1.1.11 (LIVE555 Streaming Media v2011.05.25)%@%@",KENTER,KENTER];
    72
    73
    74 [socket writeData:[options dataUsingEncoding:NSUTF8StringEncoding] withTimeout:3 tag:1];
    75 NSMutableString* readString = [[NSMutableString alloc] init];
    76 [socket readDataWithTimeout:3 tag:1];
    77
    78 return readString;
    79 }
    80
    81 /*
    82 *建立连接,返回服务器对DESCRIBE请求的响应
    83 */
    84 -(NSMutableString*)getDescribe
    85 {
    86
    87 NSMutableString* describe = [[NSMutableString alloc] init];
    88
    89 [describe appendFormat:@"DESCRIBE rtsp://%@:%d/H264 RTSP/1.0%@",SERVERADDR,SERVERPORT,KENTER];
    90 [describe appendFormat:@"CSeq: 3%@",KENTER];
    91 [describe appendFormat:@"Authorization: Basic YWRtaW4=%@",KENTER];
    92 [describe appendFormat:@"User-Agent: LibVLC/1.1.11 (LIVE555 Streaming Media v2011.05.25)%@",KENTER];
    93 [describe appendFormat:@"Accept: application/sdp%@%@",KENTER,KENTER];
    94
    95
    96
    97 [socket writeData:[describe dataUsingEncoding:NSUTF8StringEncoding] withTimeout:3 tag:1];
    98 NSMutableString* readString = [[NSMutableString alloc] init];
    99 [socket readDataWithTimeout:3 tag:2];
    100
    101
    102 return readString;
    103 }
    104
    105 /*
    106 *建立连接,返回通过tcp连接服务器对SETUP请求的响应
    107 */
    108 -(NSMutableString*)getTcpSetup
    109 {
    110
    111
    112 NSMutableString* tcpsetup = [[NSMutableString alloc] init];
    113
    114 [tcpsetup appendFormat:@"SETUP rtsp://%@:%d/H264/track1 RTSP/1.0%@",SERVERADDR,SERVERPORT,KENTER];
    115 [tcpsetup appendFormat:@"CSeq: 4%@",KENTER];
    116
    117 [tcpsetup appendFormat:@"Authorization: Basic YWRtaW4=%@",KENTER];
    118 [tcpsetup appendFormat:@"User-Agent: LibVLC/1.1.11 (LIVE555 Streaming Media v2011.05.25)%@",KENTER];
    119 [tcpsetup appendFormat:@"Transport: RTP/AVP/TCP;unicast;interleaved=0-1%@%@",KENTER,KENTER];
    120
    121
    122
    123 [socket writeData:[tcpsetup dataUsingEncoding:NSUTF8StringEncoding] withTimeout:3 tag:1];
    124 NSMutableString* readString = [[NSMutableString alloc] init];
    125 [socket readDataWithTimeout:3 tag:3];
    126
    127
    128 return readString;
    129
    130 }
    131
    132 /*
    133 *建立连接,返回通过udp连接服务器对SETUP请求的响应
    134 */
    135 -(NSMutableString*)getUdpSetup
    136 {
    137
    138 NSMutableString* udpsetup = [[NSMutableString alloc] init];
    139
    140 [udpsetup appendFormat:@"SETUP rtsp://%@/H264/track1 RTSP/1.0%@",SERVERADDR,KENTER];
    141 [udpsetup appendFormat:@"CSeq: 4%@",KENTER];
    142 [udpsetup appendFormat:@"Authorization: Basic YWRtaW4=%@",KENTER];
    143 [udpsetup appendFormat:@"User-Agent: LibVLC/1.1.11 (LIVE555 Streaming Media v2011.05.25)%@",KENTER];
    144 [udpsetup appendFormat:@"Transport: RTP/AVP;unicast;client_port=7777-7778%@%@",KENTER,KENTER];
    145
    146
    147
    148 [socket writeData:[udpsetup dataUsingEncoding:NSUTF8StringEncoding] withTimeout:3 tag:1];
    149 NSMutableString* readString = [[NSMutableString alloc] init];
    150 [socket readDataWithTimeout:3 tag:3];
    151
    152
    153 return readString;
    154
    155 }
    156
    157 /*
    158 *建立连接,返回向服务器对PLAY请求的响应
    159 */
    160 -(NSMutableString*)getPlay:(NSString*)session
    161 {
    162
    163 NSMutableString* play = [[NSMutableString alloc] init];
    164
    165 [play appendFormat:@"PLAY rtsp://%@/H264 RTSP/1.0%@",SERVERADDR,KENTER];
    166 [play appendFormat:@"CSeq: 5%@",KENTER];
    167 [play appendFormat:@"Range: npt=0.000-%@",KENTER];
    168 [play appendFormat:@"Session:%@%@",session,KENTER];
    169 [play appendFormat:@"User-Agent: LibVLC/1.1.11 (LIVE555 Streaming Media v2011.05.25)%@%@",KENTER,KENTER];
    170
    171
    172
    173 [socket writeData:[play dataUsingEncoding:NSUTF8StringEncoding] withTimeout:3 tag:1];
    174 NSMutableString* readString = [[NSMutableString alloc] init];
    175 [socket readDataWithTimeout:3 tag:4];
    176
    177
    178 return readString;
    179
    180 }
    181
    182
    183
    184 /*
    185 *建立连接,返回向服务器对TEARDOWN请求的响应
    186 */
    187 -(NSMutableString*)getTeardown:(NSString*)session
    188 {
    189
    190 NSMutableString* teardown = [[NSMutableString alloc] init];
    191
    192 [teardown appendFormat:@"TEARDOWN rtsp://%@:%d/H264 RTSP/1.0%@",SERVERADDR,SERVERPORT,KENTER];
    193 [teardown appendFormat:@"CSeq: 5%@",KENTER];
    194 [teardown appendFormat:@"Session:%@%@",session,KENTER];
    195 [teardown appendFormat:@"User-Agent: LibVLC/1.1.11 (LIVE555 Streaming Media v2011.05.25)%@%@",KENTER,KENTER];
    196
    197
    198 [socket writeData:[teardown dataUsingEncoding:NSUTF8StringEncoding] withTimeout:3 tag:1];
    199 NSMutableString* readString = [[NSMutableString alloc] init];
    200 [socket readDataWithTimeout:3 tag:5];
    201 return readString;
    202
    203 }
    204
    205 /*
    206 *返回服务器地址
    207 */
    208 -(NSString*)getServeraddr
    209 {
    210 return SERVERADDR;
    211 }
    212
    213 /*
    214 *返回RTSP回话标识,info为客户端向服务器发送setup请求时的响应信息
    215 */
    216 -(NSString*)getSession:(NSString*)info
    217 {
    218
    219 //从文件中再一行一行读取数据,将包含session的一行保留出来
    220 NSString *tmp;
    221 NSArray *lines; /*将文件转化为一行一行的*/
    222 lines = [info componentsSeparatedByString:@"\r\n"];
    223
    224 NSEnumerator *nse = [lines objectEnumerator];
    225 NSString* session = [[NSString alloc] init];
    226 while(tmp = [nse nextObject]) {
    227 if ([tmp hasPrefix:@"Session:"]) {
    228 //tmp为包含session那一行的
    229 NSInteger len = @"Session:".length;
    230 session = [[tmp substringFromIndex:len] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    231 NSLog(@"Session:%@\n",session);
    232 break;
    233 }
    234 }
    235
    236 return session;
    237
    238 }
    239
    240 /*
    241 *返回RTSP回话的Content-Base
    242 */
    243 -(NSString*)getContentBase:(NSString*)info
    244 {
    245 //info为Describe请求所响应的信息
    246 NSString *tmp;
    247 NSArray *lines; /*将文件转化为一行一行的*/
    248 lines = [info componentsSeparatedByString:@"\r\n"];
    249
    250 NSEnumerator *nse = [lines objectEnumerator];
    251 NSString* contentbase = [[NSString alloc] init];
    252 while(tmp = [nse nextObject]) {
    253 if ([tmp hasPrefix:@"Content-Base:"]) {
    254 //tmp为包含session那一行的
    255 NSInteger len = @"Content-Base:".length;
    256 contentbase = [[info substringFromIndex:len] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    257 NSLog(@"Content-Base:%@\n",contentbase);
    258 break;
    259 }
    260 }
    261
    262 return contentbase;
    263
    264 }
    265
    266
    267 /*
    268 *返回RTSP回话的Content-Type
    269 */
    270 -(NSString*)getContentType:(NSString*)info
    271 {
    272
    273 //info为Describe请求所响应的信息
    274 NSString *tmp;
    275 NSArray *lines; /*将文件转化为一行一行的*/
    276 lines = [info componentsSeparatedByString:@"\r\n"];
    277
    278 NSEnumerator *nse = [lines objectEnumerator];
    279 NSString* contenttype = [[NSString alloc] init];
    280 while(tmp = [nse nextObject]) {
    281 if ([tmp hasPrefix:@"Content-Type:"]) {
    282 //tmp为包含session那一行的
    283 NSInteger len = @"Content-Type:".length;
    284 contenttype = [[info substringFromIndex:len] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    285 NSLog(@"CContent-Type:%@\n",contenttype);
    286 break;
    287 }
    288 }
    289
    290 return contenttype;
    291
    292 }
    293
    294
    295
    296 /*
    297 *返回RTSP回话的contentlength
    298 */
    299 -(NSString*)getContentLength:(NSString*)info
    300 {
    301
    302 //info为Describe请求所响应的信息
    303 NSString *tmp;
    304 NSArray *lines; /*将文件转化为一行一行的*/
    305 lines = [info componentsSeparatedByString:@"\r\n"];
    306
    307 NSEnumerator *nse = [lines objectEnumerator];
    308 NSString* contentlength = [[NSString alloc] init];
    309 while(tmp = [nse nextObject]) {
    310 if ([tmp hasPrefix:@"Content-Type:"]) {
    311 //tmp为包含session那一行的
    312 NSInteger len = @"Content-Type:".length;
    313 contentlength = [[info substringFromIndex:len] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    314 NSLog(@"CContent-Type:%@\n",contentlength);
    315 break;
    316 }
    317 }
    318 return contentlength;
    319 }
    320
    321 /*
    322 *本机作为客户端连接接受服务器发送的消息
    323 */
    324 -(void)RecvUDPData{
    325
    326 socketudp = [[AsyncUdpSocket alloc] initWithDelegate:self];
    327
    328 [socketudp bindToPort:7777 error:nil];
    329 [socketudp enableBroadcast:YES error:nil];//设置为广播
    330
    331 if ([socketudp connectToHost:@"172.16.108.200" onPort:6970 error:nil]) {
    332 [socketudp receiveWithTimeout:-1 tag:1];//将不断接受摄像头发送的数据
    333 }
    334
    335 }
    336
    337 #pragma mark AsyncSocketDelegate
    338 /*
    339 *通过主机名和端口号连接服务器
    340 */
    341 - (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port{
    342 NSLog(@"did connect to host");
    343 }
    344 /*
    345 *向内存中写入数据
    346 */
    347 - (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{
    348 NSString *message;
    349 NSString* info = [[NSString alloc] init];
    350 switch (tag) {
    351 case 1:
    352 NSLog(@"getOptions:did read data");
    353 message = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    354 NSLog(@"message is: \n%@",message);
    355 [self getDescribe];
    356 break;
    357 case 2:
    358 NSLog(@"getDescribe:did read data");
    359 message = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    360 NSLog(@"message is: \n%@",message);
    361 info = [self getUdpSetup];
    362 break;
    363 case 3:
    364 NSLog(@"getUdpSetup:did read data");
    365 message = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    366 NSLog(@"message is: \n%@",message);
    367 NSString* session = [self getSession:info];
    368 [self getPlay:session];
    369 break;
    370 case 4:
    371 NSLog(@"getPlay:did read data");
    372 message = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    373 NSLog(@"message is: \n%@",message);
    374 [self RecvUDPData];
    375 break;
    376 case 5:
    377 NSLog(@"getTeardown:did read data");
    378 message = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    379 NSLog(@"message is: \n%@",message);
    380 break;
    381 default:
    382 break;
    383 }
    384
    385
    386
    387 }
    388
    389
    390
    391
    392 #pragma mark AsyncUdpSocketDelegate
    393 - (BOOL)onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port
    394 {
    395 NSLog(@"333333333");
    396 NSString *theLine=[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; //Convert the UDP data to an NSString
    397
    398 NSLog(@"%@", theLine);
    399
    400 [theLine release];
    401
    402 [socketudp receiveWithTimeout:-1 tag:1];
    403
    404
    405 return YES;
    406
    407 }
    408
    409
    410 @end

    建立UDP会话后,摄像头开始向客户端发送RTP数据包,多包构成一帧数据,然后进行解码显示。

  • 相关阅读:
    使用WLC+Portal完成认证
    WLAN PSK认证
    Bug搬运工-flexconnect AP losing Vlan mapping and fall back to default vlan
    Catalyst 9400配置StackWise Virtual
    如何在Wave2 AP上更改时区
    VMware Workstation导入ova镜像文件时报错?
    Password Recovery on Cisco Catalyst 3850
    Mobility Express初始化和升级
    C9300升级-TFTP
    查看WLC的SFP模块信息
  • 原文地址:https://www.cnblogs.com/foxmin/p/2392523.html
Copyright © 2020-2023  润新知