VBSOCKET实现文件传输.docx
- 文档编号:28640962
- 上传时间:2023-07-19
- 格式:DOCX
- 页数:13
- 大小:17.81KB
VBSOCKET实现文件传输.docx
《VBSOCKET实现文件传输.docx》由会员分享,可在线阅读,更多相关《VBSOCKET实现文件传输.docx(13页珍藏版)》请在冰豆网上搜索。
VBSOCKET实现文件传输
VB中使用WinSock控件传送文件
传送文件对于网络编程来说是基本的功能,比如远程控制软件。
在编制一个软件时,我从网上下了很多传文件的程序,这些程序提供的传文件功能根本就不能用。
传文本还可以,传二进制文件根本就不行。
因此,作为一个基本的功能模块,有必要单独介绍一下。
首先,在VB中要传送字符串,你可以这样写:
DimstrDataAsString
strData="Test"
但是如果你传送的二进制文件,你还能用String变量来存放吗?
从理论上分析是不行的,我也做了实验,确实是不行的。
文件虽然可以传,但是接受的文件和发送的不一样,原因可能是二进制文件里可以有任何"字符",但是不是所有的字符都可以放在String变量里。
除了String类型的变量,VB中其他类型的变量都只有几个字节长,难道一次只能发几个字节吗?
那样岂不是要累死机器了!
其实,情况没有那么悲观,我们完全可以使用数组来解决这个问题,就是使用byte数组。
把要传送的文件都读到数组里,然后发送出去。
程序如下:
FileName为要传送的文件名,WinS为发送文件的WinSock控件。
这是一个发送端的程序。
PublicSubSendFile(FileNameAsString,WinSAsWinsock)
DimFreeFAsInteger'空闲的文件号
DimLenFileAsLong'文件的长度
DimbytData()AsByte'存放数据的数组
FreeF=FreeFile'获得空闲的文件号
OpenFileNameForBinaryAs#FreeFile'打开文件
DoEvents
LenFile=LOF(FreeF)'获得文件长度
ReDimbytData(1ToLenFile)'根据文件长度重新定义数组大小
Get#FreeF,,bytData'把文件读入到数组里
Close#FreeF'关闭文件
'发送数据
EndSub
接受端的程序如下:
PrivateSubWinsock1_DataArrival(ByValbytesTotalAsLong)
DimbytData()AsByte
Dimf
f=FreeFile
OpenstrFileNameForBinaryAs#f
ReDimbytData(1TobytesTotal)
Put#f,i,bytData
i=i+bytesTotal'保证每次写都是在文件的末尾,i是个全局变量
Close#f
EndSub
这里有两个需要注意的地方,ReDimPreservebytData(1ToLenFile),下标是从1开始的,如果你写成ReDimbytData(LenFile),下标就是从0开始了,数组就有LenFile+1长了。
LenFile=LOF(FreeFile)中的LOF是获得文件长度的函数,是VB里带的,我见过很多例子用API,或者循环的读直到末尾来获取文件长度,这样都是很麻烦的,使用LOF函数就可以了。
这样的程序,即可以传送文本文件,也可以传送二进制文件。
但是你有没有发现这个程序的问题呢?
如果我要传送一个50M的文件呢?
系统可以为bytData分配50M的内存空间吗?
于是笔者拿一个50M的文件做实验吧,接收到的文件和原来的文件不一样,比原来的大。
问题出在那呢?
首先,根据文件大小重新定义bytData数组的大小本身就有问题,系统是不可能无限制的给数组分配空间的,即使可以,也会造成系统响应变慢。
在传50M文件的时候,系统就跟死机了一样。
那么怎么解决这个问题呢,一个自然的想法就是把数据分段传送。
程序如下:
发送程序,iPos是个全局变量,初始值为0。
这个变量保存着当前数据的位置。
ConstiMax=65535是每个数据块的大小。
dimiposaslong
ConstiMax=65535
DimFreeFAsInteger'空闲的文件号
DimLenFileAsLong'文件的长度
DimbytData()AsByte'存放数据的数组
FreeF=FreeFile'获得空闲的文件号
OpenFileNameForBinaryAs#FreeF'打开文件
DoEvents
LenFile=LOF(FreeF)'获得文件长度
IfLenFile<=iMaxThen'如果要发送的文件小于数据块大小,直接发送
ReDimbytData(1ToLenFile)'根据文件长度重新定义数组大小
Get#FreeF,,bytData'把文件读入到数组里
Close#FreeF'关闭文件
'发送数据
ExitSub
EndIf
'文件大于数据块大小,进行分块发送
DoUntil(iPos>=(LenFile-iMax))'发送整块数据的循环
ReDimbytData(1ToiMax)
Get#FreeF,iPos+1,bytData
iPos=iPos+iMax'移动iPos,使它指向下来要读的数据
Loop
'这里要注意的是,必须检查文件有没有剩下的数据,如果文件大小正好等于数据块大小的
'整数倍,那么就没有剩下的数据了
ReDimbytData(1ToLenFile-iPos)'发送剩下的不够一个数据块的数据
Get#FreeF,iPos+1,bytData
Close#FreeF
下面是接收端的程序:
PrivateSubWinsock1_DataArrival(ByValbytesTotalAsLong)
DimbytData()AsByte
DimlLenFileAsLong
Dimf
f=FreeFile
OpenstrFileNameForBinaryAs#f'strFileName是文件名
lLenFile=LOF(f)
ReDimbytData(1TobytesTotal)
IflLenFile=0Then'lLenFile=0表示是第一次打开文件,这里有个问题,就是'如果如果该文件存在的话,就会出错,应该在打开前检查文件是否存在。
(这里我省略了)
Put#f,1,bytData
Else
Put#f,lLenFile+1,bytData
EndIf
Close#f
EndSub
VBSOCKET实现文件传输支持断点续传
OptionExplicit
ConstPACKSIZEAsLong=65536'每包大小为64K
PrivatefilepathAsString
PrivatefilenameAsString
PrivatefilelengthAsLong'存储文件信息
Privatedata()AsByte
PrivatepackAsLong
PrivatesendedDataAsLong'数据缓冲区,文件包数,已传输的数据
PrivatealreadySendAsBoolean
PrivatecmsStrAsString
ConstfileDAsString="D:
\NMSPlugin\source\"
PrivateSubcmdConnectClient_Click()
=sckTCPProtocol
=
=8080
'连接客户端
EndSub
PrivateSubcmdSendFile_Click()
OpenfileDForBinaryAs#3
filename=""
filelength=LOF(3)
Close#3
("NMSP_AYUREADY")
EndSub
PrivateSubWinsockSend_Connect()
="已与客户端建立连接。
"
EndSub
'"发送文件"按钮事件代码:
PrivateSubsendFile()
DimiAsInteger
DimjAsLong
DimmAsLong
filepath=fileD
="向客户端传送文件:
"&filename&"大小为:
"&filelength
'计算需要传输文件的包数
pack=(filelength-sendedData)\PACKSIZE
If((filelength-sendedData)ModPACKSIZE)<>0Then
pack=pack+1
EndIf
Ifpack=0Then
pack=pack+1
EndIf
'传输文件
OpenfilepathForBinaryAs#1
Fori=1Topack
'如果只有一包
Ifpack=1Then
"filename="&filename&"|filelength="&filelength&"|send="&sendedData
ReDimdata(filelength-sendedData)
'读取数据
Forj=sendedData+1Tofilelength
Get#1,j,data(j-sendedData)
Next
'更新已传输文件的数据
sendedData=filelength
'发送文件数据
'如果是最后一包
ElseIfi+1=packThen
'读取最后一包的数据
ReDimdata(filelength-sendedData)
Forj=1Tofilelength-sendedData
Get#1,sendedData+j,data(j)
Next
'发送文件数据
'更新已传输文件的数据
sendedData=filelength
ExitFor
Else
'将文件数据放到数据缓冲区
ReDimdata(PACKSIZE)
Form=1ToPACKSIZE
Get#1,sendedData+m,data(j)
Next
'发送文件数据
'更新已传输文件的数据
sendedData=sendedData+PACKSIZE
EndIf
=Int((sendedData/filelength)*100)
Next
=Int((sendedData/filelength)*100)
Close#1
alreadySend=False
EndSub
'客户端反馈
PrivateSubWinsockSend_DataArrival(ByValbytesTotalAsLong)
DimcmdStrAsString
vbString
IfMid(cmdStr,1,13)="NMSP_IAMREADY"Then'客户端已准备好接收时,要求客户端报告已经接收的文件大小
"NMSP_RPTCURLE"&filename
ElseIfMid(cmdStr,1,13)="NMSP_REQFILEN"Then'客户端要求发送文件名称
"NMSP_FILENAME="&filename
ElseIfMid(cmdStr,1,13)="NMSP_REQFILES"Then'客户端要求发送文件大小
"NMSP_FILESIZE="&filelength',vbLong
ElseIfMid(cmdStr,1,13)="NMSP_RECEIVED"Then'收到客户端已经接收到的文件大小报告
"客户端已经接收了"&Mid(cmdStr,14,Len(cmdStr))
sendedData=Mid(cmdStr,15,Len(cmdStr))
Iffilelength=sendedDataThen
"NMSP_SENDDONE"
'初始化文件名,大小,已接收大小,遍历是否还需要向别的客户端发送
Letfilename=""
Letfilelength=0
LetsendedData=0
="文件发送完毕!
"
Else
CallsendFile
EndIf
EndIf
EndSub
'==========================================================客户端======================================================
OptionExplicit
DimflagAsBoolean'设置是否继续接收文件的开关标识
PrivatereadyReceiveAsBoolean
PrivatefilenameAsString
PrivatetempfileAsString
PrivaterealfileAsString
PrivatereveivePathAsString
PrivatefilelengthAsLong'存储文件信息
Privatedata()AsByte,receivedAsLong'声明数据缓冲区和已接收的数据
PrivateSubForm_Load()
reveivePath=&"\received\"
=sckTCPProtocol
=8080
CallinitReceiveState
EndSub
PrivateSubWinsockReceive_Connect()
="已经连接到服务器"
EndSub
PrivateSubWinsockReceive_ConnectionRequest(ByValrequestIDAsLong)
<>0Then
EndIf
="已接受连接请求。
"
EndSub
PrivateSubWinsockReceive_DataArrival(ByValbytesTotalAsLong)
DimjAsLong
'分别接收传输文件的文件名、文件长度
',vbString,bytesTotal-4
',vbLong
'判断指令类型
IfreadyReceive=FalseThen
DimcmdStrAsString
vbString
IfMid(cmdStr,1,13)="NMSP_AYUREADY"Then'询问是否准备好接收文件
Iffilename=""Then
("NMSP_REQFILEN")
ElseIffilelength=0Then
("NMSP_REQFILES")
Else
("NMSP_IAMREADY")
EndIf
ElseIfMid(cmdStr,1,13)="NMSP_FILENAME"Then'文件名
filename=Mid(cmdStr,15,Len(cmdStr))
("NMSP_REQFILES")
ElseIfMid(cmdStr,1,13)="NMSP_FILESIZE"Then'文件大小
filelength=Mid(cmdStr,15,Len(cmdStr))
If(filelength<>0)Then
("NMSP_IAMREADY")
EndIf
ElseIfMid(cmdStr,1,13)="NMSP_RPTCURLE"Then'服务器端要求提供已经接收的文件大小
'为传输文件设置临时文件
realfile=reveivePath&filename
tempfile=reveivePath&filename&".td"
'返回已接收的数据
'OpenrealfileForBinaryAs#1
OpentempfileForBinaryAs#2
IfLOF
(2)>0Then
Input#2,received
"received="&received
EndIf
Close#2
"NMSP_RECEIVED="&received
readyReceive=True
="准备接收文件:
"&filename&"大小为:
"&filelength
ElseIfMid(cmdStr,1,14)="NMSP_SENDDONE="Then
'服务器发送文件完毕执行安装操作
EndIf
Else
realfile=reveivePath&filename
tempfile=reveivePath&filename&".td"
="正在接收文件:
"&filename&"保存到:
"&realfile
'返回已接收的数据
OpenrealfileForBinaryAs#1
OpentempfileForBinaryAs#2
'建立数据缓冲区
ReDimdata(bytesTotal)
'接收服务器端传输的数据
vbArray+vbByte
'将接收的数据写入文件
Forj=received+1Toreceived+bytesTotal
Put#1,j,data(j-received-1)
Put#2,j,data(j-received-1)
Next
'更新已接收的数据
received=received+bytesTotal
'更新临时文件
'Write#2,received
=Int((received/filelength)*100)
'传输完毕
>=100Then
="数据传输完毕!
"
Close#2
'删除临时文件
Kill(tempfile)
Close#1
CallinitReceiveState
EndIf
Close#1
Close#2
EndIf
EndSub
PrivateSubinitReceiveState()
readyReceive=False
received=0
filelength=0
filename=""
="监听中"
EndSub
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- VBSOCKET 实现 文件传输