5. 媒体服务传输控件
1) 类型
– 多播
一对多的文件传输, 接受者"监听"同一个多播ip地址和端口来接收文件.
– 单播
一对一的文件传输, 接受者"监听"多个ip地址之一和同一个断开来接收文件.
2) 完全可靠性服务
文件传输组件实现了一个多播的完全可靠性服务保证每一个数据包被收到, 保持不被破坏和完整. 如果接受者发现数据包丢失和损坏, 可以发送一个nak到发送者请求数据包重发.
在完全可靠性服务模式下, 文件传输服务执行一个流控制; 这是对于速度控制的额外支持. 如果发送者传输数据包过快, 接受者发送一个扼杀nak提示传输速度必须下降. 接受者也在忙和无法接收更多数据包或者一段时间没有收到数据包的时候发送空闲 nak.
文件传输控件使用完全可靠性服务模式作为缺省模式. 如果发送者不实用该模式, 控件依旧可以接收回传只是无法请求重传数据包. 完全可靠性服务可以通过 fullyreliableservice 属性关闭.
双向网要求完全可靠服务.
完全可靠服务模式要求使用错误转发机制(fec).
【相关控制消息】
– nak
是一个发送自接收端到发送端的数据, 提示数据包被放弃. 是一个请求重发数据包的消息. 使用它是一个有效地方式添加可信度, 因为接受者只需要接收那些没有被接收的数据包.
– throttle nak
来自接收端的请求, 提示发送端降低带宽. 被完全可靠服务使用.
– idle nak
来自接收端的请求, 提示发送端在数据包没有收到, 且传输不完整. 发送端收到的时候等待其他接收端nkas来重发请求的数据包.
3) 接收文件
方式:
1. 在发送者发送文件之前, 启动一个接收操作确保所有的文件被传输. 如果接收操作在发送到已经开始发送一组文件后开始, 接收端接收当前文件和其余文件. 如果接收动作在发送途中开始, 接收端接收该文件.
2. 使用 ftsstartfiletransferreceive 方法接收文件. 称之为监听. 针对多播传输, 使用一个多播地址. 针对多播传输使用主机的本地地址之一, 如果没有指定本地地址, 第一个主机本地地址缺省使用. 接收端可以取消一个文件接收(ftscancelfiletransferreceive).
状态和进度可以通过事件和属性在文件传输期间获得.
4) 状态提示
ftsontransferstarted
ftsontransfercompleted
ftsonfiletransferstarted
ftsonfiletransfercompleted
ftsonstatuschanged
5) 进度提示
要获得文件传输信息, 使用 ftsregisterstatuscallback 注册需要的传输信息. 典型的请求包括 – 每100kb提示一次, 获则每10%提示一次.
提示也可以请求关于接收的数据包个数, 虚假数据包个数( 从同一个ip地址和端口获得, 但是不是需要的文件部分), 重复数据包, 丢失数据包等. 进度提示由 ftsontransferprogress 事件处理. 读取正确的属性, 然后在事件处理子程序中采取正确的处理. 通过调用 ftsrevokestatuscallback 方法可以宣告一个提示无效.
进度通告只在 ftsontransferprogress 时间上触发. 传输进度属性值 (诸如: numpacketsdropped)总是有效地.
6) 如何使用
<object id="nsfile" width="100" height="51" classid="clsid:26f24a93-1da2-11d0-a334-00aa004a5fc5" codebase="http://activex.microsoft.com/activex/controls/mplayer/en/nsftsinf.cab#version=3,0,0,2700"></object>
<!– 一个接收文件的例子, 附带进度显示 –>
<script language="vbscript">
<!–
sub btnreceivefile_onclick
myform.noise.value = 0
myform.redundancy.value = 0
call nsfile1.ftsregisterstatuscallback(0, 0, 4096, 4096, 0, 0, 0, 0, 0, 0, 0)
on error resume next
call nsfile1.ftsstartfiletransferreceive("239.230.50.50", 5050, "", "%temp%\", 0, 1025)
if err.number then msgbox "start error = " & returnerror(err.number)
end sub
sub btncancelfile_onclick
call nsfile1.ftscancelfiletransferreceive
msgbox "transfer cancelled. error = " & returnerror(nsfile1.result)
end sub
sub nsfile1_ftsontransferprogress
myform.totalbytes.value = nsfile1.numtotalbytestransferred
myform.databytes.value = nsfile1.numtotaldatabytestransferred
myform.packets.value = nsfile1.numpacketstransferred
myform.bogus.value = nsfile1.numboguspacketsreceived
end sub
sub nsfile1_ftsontransfercompleted
msgbox "transfer completed. error = " & returnerror(nsfile1.result)
totalbytes = nsfile1.numtotalbytestransferred
if totalbytes > 0 then
databytes = nsfile1.numtotaldatabytestransferred
myform.redundancy.value = int(((totalbytes – databytes)/totalbytes)*100)
packets = nsfile1.numpacketstransferred
bogus = nsfile1.numboguspacketsreceived
myform.noise.value = int(bogus/packets)
myform.totalbytes.value = nsfile1.numtotalbytestransferred
myform.databytes.value = nsfile1.numtotaldatabytestransferred
myform.packets.value = nsfile1.numpacketstransferred
myform.bogus.value = nsfile1.numboguspacketsreceived
end if
end sub
sub btnabout_onclick
call nsfile1.aboutbox()
end sub
function returnerror(byval errnum)
select case errnum
case 0
errstring = "no error"
case 1
errstring = "already requested"
case -2147467260
errstring = "cancelled"
case -2147467259
errstring = "failed"
case -2147287038
errstring = "file not found"
case -2147024882
errstring = "out of memory"
case -2147024809
errstring = "invalid parameter"
case -2147023436
errstring = "timed out"
case else
errstring = "unknown error " & cstr(hex(errnum))
end select
returnerror = errstring
end function
–>
</script>
<!– 一个完整的接收文件例子 –>
<html>
<head><title>total fts demo</title>
<link rel="stylesheet" type="text/css" href="../msdn_ie4.css">
</head>
<body bgcolor="#ffffff">
<h2>total file transfer service demo</h2>
<object id="nsfile1"
codebase="http://activex.microsoft.com/activex/controls/mplayer/en/nsftsinf.cab#version=3,0,0,2700"
classid="clsid:26f24a93-1da2-11d0-a334-00aa004a5fc5" align="right" height="10" width="10">
<param name="_version" value="65536">
<param name="_extentx" value="2646">
<param name="_extenty" value="1323">
<param name="_stockprops" value="0">
</object>
<form name="myform">
<table>
<tr>
<td><b>source ip:</b></td><td><input type="text" name="ipaddr" value="239.230.50.50"></td>
<td><b>source port:</b></td><td><input type="text" name="ipport" value="5050" size="6"></td>
<td><b>filter:</b></td><td><input type="text" name="filter"></td>
</tr>
</table>
<hr size=1>
<table>
<tr>
<td><b>path:</b></td><td><input type="text" name="filepath" value="%temp%\"></td>
<td><b>attributes:</b></td><td><input type="text" name="attributes" value="0"></td>
<td><b>flags:</b></td><td><input type="text" name="flags" value="1025"></td>
</tr>
</table>
<hr size=1>
<table>
<tr>
<td><input type="button" name="btnreceivefile" value="start receive"></td>
<td><input type="button" name="btncancelfile" value="cancel"></td>
<td><input type="button" value="about fts" name="btnabout"></td>
<td width="25"></td>
<td width="50"><input type="text" name="routing"></td>
<td width="25"></td>
<td align="right" width="75"><b>start time:</b></td>
<td width="150"><input type="text" name="starttime"></td>
</tr>
</table>
<hr size=1>
<table>
<tr>
<td><b>files:</b></td><td><input type="text" name="numfiles" size="5"></td>
<td><b>percent file:</b></td><td><input type="text" name="perfiledata" size="30"></td>
<td><b>time taken:</b></td><td><input type="text" name="mytime"></td>
</tr>
</table>
<hr size=1>
<table>
<tr>
<td><b>current file:</b></td><td><input type="text" name="currfile" size="30"></td>
<td><b>size:</b></td><td><input type="text" name="currsize" size="16"></td>
<td><b>attributes:</b></td><td><input type="text" name="currattr" size="6"></td>
</tr>
</table>
<hr size=1>
<table>
<tr>
<td><b>total bytes:</b></td><td><input type="text" name="totalbytes"></td>
<td><b>data bytes:</b></td><td><input type="text" name="databytes"></td>
</tr>
<tr>
<td><b>packets:</b></td><td><input type="text" name="packets" size="8"></td>
<td><b>bogus:</b></td><td><input type="text" name="bogus" size="8"></td>
<td><b>drop:</b></td><td><input type="text" name="packdrop" size="8"></td>
</tr>
<tr>
<td><b>corr:</b></td><td><input type="text" name="packcorr" size="8"></td>
<td><b>dupes:</b></td><td><input type="text" name="packdup" size="8"></td>
</tr>
</table>
<hr size=1>
<table>
<tr>
<td><b>source path:</b></td><td><input type="text" name="srcpath" size="35"></td>
</tr>
<tr>
<td><b>destination path:</b></td><td><input type="text" name="destpath" size="35"></td>
</tr>
<tr>
<td><b>endpoint address:</b></td><td><input type="text" name="endaddr" size="16"></td>
<td><b>endpoint port:</b></td><td><input type="text" name="endport" size="8"></td>
</tr>
<tr>
<td><b>source addresss:</b></td><td><input type="text" name="srcaddr" size="16"></td>
<td><b>source port:</b></td><td><input type="text" name="srcport" size="8"></td>
</tr>
<tr>
<td><b>local address:</b></td><td><input type="text" name="locaddr" size="16"></td>
<td><b>local port:</b></td><td><input type="text" name="locport" size="8"></td>
</tr>
<tr>
<td><b>local port used:</b></td><td><input type="text" name="lastport" size="16"></td>
</tr>
</table>
<hr size=1>
</form>
<script language="vbscript">
<!–
sub btnreceivefile_onclick
on error resume next
— initialize form values.
myform.mytime.value = ""
myform.starttime.value = ""
myform.numfiles.value = ""
myform.perfiledata.value = ""
myform.totalbytes.value = ""
myform.databytes.value = ""
myform.currfile.value = ""
myform.currattr.value = ""
myform.currsize.value = ""
myform.packets.value = ""
myform.bogus.value = ""
myform.packdrop.value = ""
myform.packcorr.value = ""
myform.packdup.value = ""
myform.srcpath.value = ""
myform.destpath.value = ""
myform.endaddr.value = ""
myform.endport.value = ""
myform.srcaddr.value = ""
myform.srcport.value = ""
myform.locaddr.value = ""
myform.locport.value = ""
myform.lastport.value = ""
— determine routing.
if myform.ipaddr.value = "" then
myform.routing.value = " listen for unicast"
myipaddr = ""
nsfile1.type = 2
else
myipaddr = myform.ipaddr.value
myform.routing.value = "listen for multicast"
end if
— set up callbacks.
call nsfile1.ftsregisterstatuscallback(4096, 5, 8192, 8192, 1, 1, 1, 1, 1, 4+8+16+32, 0)
— start transfer.
call nsfile1.ftsstartfiletransferreceive(myipaddr, myform.ipport.value, myform.filter.value, myform.filepath.value, myform.attributes.value, myform.flags.value)
if err.number then msgbox "start error = " & returnerror(err.number)
end sub
sub btncancelfile_onclick
on error resume next
call nsfile1.ftscancelfiletransferreceive
msgbox "transfer cancelled. error = " & returnerror(nsfile1.result)
end sub
sub nsfile1_ftsontransferstarted
on error resume next
myform.starttime.value = time()
myform.srcpath.value = nsfile1.sourcefilepath
myform.destpath.value = nsfile1.destinationfilepath
myform.endaddr.value = nsfile1.endpointaddress
myform.endport.value = nsfile1.endpointport
myform.srcaddr.value = nsfile1.sourceaddress
myform.srcport.value = nsfile1.sourceport
myform.locaddr.value = nsfile1.localaddress
myform.locport.value = nsfile1.localport
myform.lastport.value = nsfile1.localportused
end sub
sub nsfile1_ftsonfiletransferstarted
on error resume next
myform.currfile.value = nsfile1.currentfilepath
myform.currattr.value = nsfile1.currentfileattributes
myform.currsize.value = nsfile1.currentfilesize
end sub
sub nsfile1_ftsonfiletransfercompleted
on error resume next
myform.numfiles.value = nsfile1.numfilestransferred
end sub
sub nsfile1_ftsontransferprogress
on error resume next
myform.numfiles.value = nsfile1.numfilestransferred
progbar = int((nsfile1.percentfiledatabytestransferred)/5)
if progbar < 20 then
myform.perfiledata.value = string(progbar, "?)
else
myform.perfiledata.value = "file transferred!"
end if
myform.totalbytes.value = nsfile1.numtotalbytestransferred
myform.databytes.value = nsfile1.numtotaldatabytestransferred
myform.packets.value = nsfile1.numpacketstransferred
myform.bogus.value = nsfile1.numboguspacketsreceived
myform.packdrop.value = nsfile1.numpacketsdropped
myform.packcorr.value = nsfile1.numpacketscorrected
myform.packdup.value = nsfile1.numduplicatepacketsreceived
end sub
sub nsfile1_ftsontransfercompleted
on error resume next
ttime = timevalue(now) – timevalue(myform.starttime.value)
myform.mytime.value = "total = " & hour(ttime) & " h " & minute(ttime) & " m " & second(ttime) & " s"
msgbox "transfer completed. error = " & returnerror(nsfile1.result)
— bytes
myform.numfiles.value = nsfile1.numfilestransferred
myform.perfiledata.value = "file transferred!"
myform.totalbytes.value = nsfile1.numtotalbytestransferred
myform.databytes.value = nsfile1.numtotaldatabytestransferred
myform.currfile.value = nsfile1.currentfilepath
myform.currattr.value = nsfile1.currentfileattributes
myform.currsize.value = nsfile1.currentfilesize
— packets
myform.packets.value = nsfile1.numpacketstransferred
myform.bogus.value = nsfile1.numboguspacketsreceived
myform.packdrop.value = nsfile1.numpacketsdropped
myform.packcorr.value = nsfile1.numpacketscorrected
myform.packdup.value = nsfile1.numduplicatepacketsreceived
end sub
sub btnabout_onclick
call nsfile1.aboutbox()
end sub
function returnerror(byval errnum)
select case errnum
case 0
errstring = "no error"
case 1
errstring = "already requested"
case -2147467260
errstring = "cancelled"
case -2147467259
errstring = "failed"
case -2147287038
errstring = "file not found"
case -2147024882
errstring = "out of memory"
case -2147024809
errstring = "invalid parameter"
case -2147023436
errstring = "timed out"
case else
errstring = "unknown error " & cstr(hex(errnum))
end select
returnerror = errstring
end function
–>
</script>
</body>
</html>
