交互过程
对于数据流和控制流,BMTP协议都使用了服务器的1680端口,实际上这个端口在网页javascript脚本中是给出的。例如:
diskList[0] = new CDiskObj(1,'disk_vodserv_1',1,'vodserv_1','202.113.112.139:1680');
可以看到,这里的javascript语句提供了服务器地址和提供服务的端口号。为了简便,可以将端口号1680与域名vod.hebut.edu.cn硬编码到程序代码中。
总体流程:
- 获取视频信息
BMTP协议的请求类似于一个HTTP请求,例如:
GET / HTTP/1.0
Accept: */*
User-Agent: BMTPAgent
Host: VOD
...
PID:111
SID:1
DID:1
PFG:1
MGC:*************
...
上面的请求中包含五个关键值:pid,sid,did,pfg,mgc。MGC是由pid,sid,did,pfg带入字符串求取md5 hash而得到的。pid,sid,did,pfg四个值是节目信息网页中的javascript给出的,例如:
sitcomList[0] = new CSitcomObj(7437,1507,1,'[CQMF]士兵突击.国语中字.01.V-vb','',1,1,1,0,0,'00:00:00','00:00:00');
CSitcomObj
的第2、3个参数分别是pid与sid,did、pfg经测试始终设置为did=1,pfg=0即可。然后通过计算hash值,伪代码如下:
mgc=md5("boful+pid=%d;sid=%d;did=%d;fil=;pfg=%d;truran",pid,sid,did,pfg);
将构造好的请求发送到服务器,可以获得一个长度为332字节的信息,结构如下:
struct{ char MGC_DW[6]; char nop1[6]; uint32 cid; uint32 usn; char nop2[32]; char time[20]; char videoname[88]; char fileext[8]; char nop4[203]; }
在大数端的cpu上,可以直接套用上面的数据结构。某些ARM/MIPS CPU可能需要自行重组cid与usn。
- 控制命令
在BMTP协议中存在3种控制命令,在WAY=1时,由MTD=1、2或3来控制1. MTD=1 即获取媒体信息2. MTD=2 Client每隔三秒发送一次,猜想用来确定连接状态。例如:
GET / HTTP/1.0
Accept: */*
User-Agent: BMTPAgent
Host: VOD
UGT:NETPLAYER
WAY:1
MTD:2
3. MTD=3 定位文件位置。例如:
GET / HTTP/1.0
Accept: */*
User-Agent: BMTPAgent
Host: VOD
UGT:NETPLAYER
WAY:1
MTD:3
SPL:0
SPH:0
在MTD=1或MTD=3的数据包发送后,数据流可以打开并获取数据。服务器通过cid和usn的值来确定session。为了处理方便,强制发送一个定位请求可以使后面的处理方便些。传输数据的连接通过发送如下数据可以开始接收文件内容:
GET / HTTP/1.0
Accept: */*
User-Agent: BMTPAgent
Host: VOD
UGT:NETPLAYER
WAY:2
FPT:1
CID:...
USN:...
STT:...
另外需要注意的是,服务器在发送实际数据之前会有48个字节的响应,包括8字节响应上面的数据的请求,和40字节对MTD=3定位请求的响应。所以略过48个字节之后就可以把内容写入文件了。
编程接口
- C# vodd命名空间
C#命名空间声明了三个类:downloader、constructor和MediaInfoParser。给出一个典型代码
downloader t = new downloader(1507, 1, 1, 0); t.GetMediaInfo(); t.Config.filepos = 614736; t.OnDlding += new ProcessDelegate(OnProcess); t.OnDlded+=new ProcessDelegate(OnProcessed); t.SaveToFile("c:\\" + t.Config.videoname + t.Config.fileext);
通过调用constructor的成员和MediaInfoParser,可以实现更灵活的操作。
另外需要注意的是,服务器可能对每一个MTD=1的请求都分配了session资源,所以在不准备下载相应文件时,不应该发出相应的请求,以免服务器压力过大。
- C 库函数
测试程序
两个用来测试的应用程序:下载。测试截图: