项目要求:手机的遥控器界面,通过UDP/TCP协议制定的指令,连接电视盒子,操控电视进行换台,播放,暂停,调整声音的操作,同时实现小屏投大屏,即手机播放的视频可以投到电视上播放。
做项目之前,我们需要知道
1、如何在oc中使用UDP/TCP协议,他们是什么
2、UDP/TCP指令是什么
3、我们要如何使手机和电视盒子连接
解决问题一:Socket
网络七层由下往上分别为物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。http协议对应于应用层,tcp协议对应于传输层,ip协议对应于网络层,三者本质上没有可比性。 何况HTTP协议是基于TCP连接的。TCP/IP是传输层协议,主要解决数据如何在网络中传输;而HTTP是应用层协议,主要解决如何包装数据。
我们在传输数据时,可以只使用传输层(TCP/IP),但是那样的话,由于没有应用层,便无法识别数据内容,如果想要使传输的数据有意义,则必须使用应用层 协议,应用层协议很多,有HTTP、FTP、TELNET等等,也可以自己定义应用层协议。WEB使用HTTP作传输层协议,以封装HTTP文本信息,然 后使用TCP/IP做传输层协议将它发送到网络上。Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过套接字Socket,我们才能使用TCP/IP协议。(当然关于UDP/TCP区别什么的大家应该也都了解了 这里就不赘述了么么哒)
解决问题二 指令?
所谓的指令这里也就是电视盒子端的开发人员,制定好的一种规则,例如按住遥控器的“上箭头”,可能会规定指令是“1”,只要接收到我们客户端发送“1”(当然要编码的,稍后会说哦),盒子就会执行“向上”的行为(可能是换台)。
命令
0x11111111 (app傳送操作命令)
格式: 0x11111111 + {int cmd} (操作命令)
操作命令 1:POW OFF 2:HOME 3:MUTE 4:MENU 5:RETURN 6:VOL_UP 7:VOL_DOWN 8:ARR_UP 9:ARR_DOWN 10:ARR_RIGHT 11:ARR_LEFT 12:BUT_OK
解决问题3 建立socket连接
建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket,另一个运行于服务器端,称为ServerSocket。
套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。
服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求。
客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。
连接确认:当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户 端,一旦客户端确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。
上面的可能太官方了,说白了,你需要有以下的步骤来使客户端和盒子(服务器)建立连接。
1、首先你需要发送广播,来找谁是盒子
2、找到以后,服务器会返回给你,它自己的ip和端口号
3、以后你发的指令,就往这个ip和端口号发送就好啦
那么废话不多说上代码,因为我做的项目是遵循UDP协议的,所以代码是基于UDP写的,关于Sorket这里有一个封装好的类库GCDAsyncUdpSocket,下载地址如下http://download.csdn.net/download/xiaoamani/7455735(如果你不能下载也可百度搜索,GitHub上也有但是是demo,不是只是类库,当然你也可以和我要哈)
代码代码代码
-(void)createClientUdpSocket
{
dispatch_queue_tdQueue =dispatch_get_global_queue(0,0);
//1.创建一个udp socket用来和服务器端进行通讯
sendUdpSocket= [[GCDAsyncUdpSocketalloc]initWithDelegate:selfdelegateQueue:dQueuesocketQueue:nil];
//2.banding一个端口(可选),如果不绑定端口,那么就会随机产生一个随机的电脑唯一的端口
//端口数字范围(1024,2^16-1)
[sendUdpSocketbindToPort:8085error:nil];
[sendUdpSocketenableBroadcast:YESerror:nil];
//3.等待接收对方的消息
[sendUdpSocketreceiveOnce:nil];
}
- (void) sendMsg {
intcommNum =0x55f03651;
NSMutableData*myData = [[NSMutableDataalloc]init];
[myDataappendBytes:&commNumlength:sizeof(commNum)];
NSString*host =@"255.255.255.255"; //发送广播
uint16_tport =49555;//规定的端口号
//开始发送
//改函数只是启动一次发送它本身不进行数据的发送,而是让后台的线程慢慢的发送也就是说这个函数调用完成后,数据并没有立刻发送,异步发送
[sendUdpSocketsendData:myData toHost:hostport:port withTimeout:1tag:100];
}
#pragma mark -GCDAsyncUdpSocketDelegate
-(void)udpSocket:(GCDAsyncUdpSocket*)sock didSendDataWithTag:(long)tag{
if(tag ==100) {
NSLog(@"表示标记为100的数据发送完成了");
}
}
-(void)udpSocket:(GCDAsyncUdpSocket*)sock didNotSendDataWithTag:(long)tag dueToError:(NSError*)error{
NSLog(@"标记为tag %ld的发送失败失败原因%@",tag, error);
}
//接受盒子服务器的返回端口号和ip以及一些数据
-(void)udpSocket:(GCDAsyncUdpSocket*)sock didReceiveData:(NSData*)data fromAddress:(NSData*)address withFilterContext:(id)filterContext{
NSString*ip = [GCDAsyncUdpSockethostFromAddress:address];
uint16_tport = [GCDAsyncUdpSocketportFromAddress:address];
//继续来等待接收下一次消息
_ipNum= ip;
_myPort= port;
[sockreceiveOnce:nil];
//dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//[self sendBackToHost:ip port:port withMessage:s];
//});
}
//开始向接收到的ip和端口号发送指令myIpum
- (void) sendMsgTime :(NSString*)myIpum andPort:(uint16_t)myPort andUid:(NSString*)myUid{
intcommNumber =0x11111111;
NSMutableData*myDa = [[NSMutableDataalloc]init];
[myDaappendBytes:&commNumberlength:sizeof(commNumber)];
NSString*host = myIpum;
uint16_tport = myPort;
_romeId= myUid;
//开始发送
//改函数只是启动一次发送它本身不进行数据的发送,而是让后台的线程慢慢的发送也就是说这个函数调用完成后,数据并没有立刻发送,异步发送
[sendUdpSocketsendData:myDatoHost:hostport:portwithTimeout:1tag:100];
}
ok截至到这里 大家就应该明白了如何接受服务器的数据,和发送指令。那么投屏的,道理一样,只是需要发送指令的时候,把点播视频url编码后也发送过去,直播的videoId也发送过去(至于编码我会在研究,写一篇文章,欢迎大家到时候看看指点)当然每个项目的规定不一样,我这不是一定的,只是思路大家明白就好。这是我的第一篇文章,可能会有许多的不足,希望大家指正,哈哈哈,我今年刚毕业,10月份之前公司有点变故辞职了,现在找工作几乎没面试,很多人劝我转行,说我没经验,iOS已经发展不好了,可是我觉得,如果有技术能钻研,就算不发展的那一天,我也觉得我没白学iOS,因为我得到了那份满足感,开发的满足感,我享受打码。