admin管理员组文章数量:1531347
2024年1月24日发(作者:)
VB中使用WinSock控件传送文件
传送文件对于网络编程来说是基本的功能,比如远程控制软件;在编制一个软件时,我从网上下了很多传文件的程序,这些程序提供的传文件功能根本就不能用;传文本还可以,传二进制文件根本就不行;因此,作为一个基本的功能模块,有必要单独介绍一下;
首先,在VB中要传送字符串,你可以这样写:
DimstrDataAsString
strData="Test"
但是如果你传送的二进制文件,你还能用String变量来存放吗 从理论上分析是不行的,我也做了实验,确实是不行的;文件虽然可以传,但是接受的文件和发送的不一样,原因可能是二进制文件里可以有任何"字符",但是不是所有的字符都可以放在String变量里;
除了String类型的变量,VB中其他类型的变量都只有几个字节长,难道一次只能发几个字节吗 那样岂不是要累死机器了其实,情况没有那么悲观,我们完全可以使用数组来解决这个问题,就是使用byte数组;把要传送的文件都读到数组里,然后发送出去;程序如下:
FileName为要传送的文件名,WinS为发送文件的WinSock控件;这是一个发送端的程序;
PublicSubSendFileFileNameAsString,WinSAsWinsock
DimFreeFAsInteger'空闲的文件号
DimLenFileAsLong'文件的长度
DimbytDataAsByte'存放数据的数组
FreeF=FreeFile'获得空闲的文件号
OpenFileNameForBinaryAsFreeFile'打开文件
DoEvents
LenFile=LOFFreeF'获得文件长度
ReDimbytData1ToLenFile'根据文件长度重新定义数组大小
GetFreeF,,bytData'把文件读入到数组里
CloseFreeF'关闭文件
'发送数据
EndSub
接受端的程序如下:
PrivateSubWinsock1_DataArrivalByValbytesTotalAsLong
DimbytDataAsByte
Dimf
f=FreeFile
OpenstrFileNameForBinaryAsf
ReDimbytData1TobytesTotal
Putf,i,bytData
i=i+bytesTotal'保证每次写都是在文件的末尾,i是个全局变量
Closef
EndSub
这里有两个需要注意的地方,ReDimPreservebytData1ToLenFile,下标是从1开始的,如果你写成ReDimbytDataLenFile,下标就是从0开始了,数组就有LenFile+1长了;LenFile=LOFFreeFile中的LOF是获得文件长度的函数,是VB里带的,我见过很多例子用API,或者循环的读直到末尾来获取文件长度,这样都是很麻烦的,使用LOF函数就可以了;
这样的程序,即可以传送文本文件,也可以传送二进制文件;但是你有没有发现这个程序的问题呢 如果我要传送一个50M的文件呢 系统可以为bytData分配50M的内存空间吗
于是笔者拿一个50M的文件做实验吧,接收到的文件和原来的文件不一样,比原来的大;问题出在那呢
首先,根据文件大小重新定义bytData数组的大小本身就有问题,系统是不可能无限制的给数组分配空间的,即使可以,也会造成系统响应变慢;在传50M文件的时候,系统就跟死机了一样;那么怎么解决这个问题呢,一个自然的想法就是把数据分段传送;程序如下:
发送程序,iPos是个全局变量,初始值为0;这个变量保存着当前数据的位置;ConstiMax=65535是每个数据块的大小;
dimiposaslong
ConstiMax=65535
DimFreeFAsInteger'空闲的文件号
DimLenFileAsLong'文件的长度
DimbytDataAsByte'存放数据的数组
FreeF=FreeFile'获得空闲的文件号
OpenFileNameForBinaryAsFreeF'打开文件
DoEvents
LenFile=LOFFreeF'获得文件长度
IfLenFile<=iMaxThen'如果要发送的文件小于数据块大小,直接发送
ReDimbytData1ToLenFile'根据文件长度重新定义数组大小
GetFreeF,,bytData'把文件读入到数组里
CloseFreeF'关闭文件
'发送数据
ExitSub
EndIf
'文件大于数据块大小,进行分块发送
DoUntiliPos>=LenFile-iMax'发送整块数据的循环
ReDimbytData1ToiMax
GetFreeF,iPos+1,bytData
iPos=iPos+iMax'移动iPos,使它指向下来要读的数据
Loop
'这里要注意的是,必须检查文件有没有剩下的数据,如果文件大小正好等于数据块大小的
'整数倍,那么就没有剩下的数据了
ReDimbytData1ToLenFile-iPos'发送剩下的不够一个数据块的数据
GetFreeF,iPos+1,bytData
CloseFreeF
下面是接收端的程序:
PrivateSubWinsock1_DataArrivalByValbytesTotalAsLong
DimbytDataAsByte
DimlLenFileAsLong
Dimf
f=FreeFile
OpenstrFileNameForBinaryAsf'strFileName是文件名
lLenFile=LOFf
ReDimbytData1TobytesTotal
IflLenFile=0Then'lLenFile=0表示是第一次打开文件,这里有个问题,就是'如果如果该文件存在的话,就会出错,应该在打开前检查文件是否存在;这里我省略了
Putf,1,bytData
Else
Putf,lLenFile+1,bytData
EndIf
Closef
EndSub
VBSOCKET实现文件传输支持断点续传
OptionExplicit
ConstPACKSIZEAsLong=65536'每包大小为64K
PrivatefilepathAsString
PrivatefilenameAsString
PrivatefilelengthAsLong'存储文件信息
PrivatedataAsByte
PrivatepackAsLong
PrivatesendedDataAsLong'数据缓冲区,文件包数,已传输的数据
PrivatealreadySendAsBoolean
PrivatecmsStrAsString
ConstfileDAsString="D:NMSPluginsource"
PrivateSubcmdConnectClient_Click
=sckTCPProtocol
=
=8080
'连接客户端
EndSub
PrivateSubcmdSendFile_Click
OpenfileDForBinaryAs3
filename=""
filelength=LOF3
Close3
"NMSP_AYUREADY"
EndSub
PrivateSubWinsockSend_Connect
="已与客户端建立连接;"
EndSub
'"发送文件"按钮事件代码:
PrivateSubsendFile
DimiAsInteger
DimjAsLong
DimmAsLong
filepath=fileD
="向客户端传送文件:"&filename&"大小为:"&filelength
'计算需要传输文件的包数
pack=filelength-sendedDataPACKSIZE
Iffilelength-sendedDataModPACKSIZE<>0Then
pack=pack+1
EndIf
Ifpack=0Then
pack=pack+1
EndIf
'传输文件
OpenfilepathForBinaryAs1
Fori=1Topack
'如果只有一包
Ifpack=1Then
"filename="&filename&"|filelength="&filelength&"|send="&sendedData
ReDimdatafilelength-sendedData
'读取数据
Forj=sendedData+1Tofilelength
Get1,j,dataj-sendedData
Next
'更新已传输文件的数据
sendedData=filelength
'发送文件数据
'如果是最后一包
ElseIfi+1=packThen
'读取最后一包的数据
ReDimdatafilelength-sendedData
Forj=1Tofilelength-sendedData
Get1,sendedData+j,dataj
Next
'发送文件数据
'更新已传输文件的数据
sendedData=filelength
ExitFor
Else
'将文件数据放到数据缓冲区
ReDimdataPACKSIZE
Form=1ToPACKSIZE
Get1,sendedData+m,dataj
Next
'发送文件数据
'更新已传输文件的数据
sendedData=sendedData+PACKSIZE
EndIf
=IntsendedData/filelength100
Next
=IntsendedData/filelength100
Close1
alreadySend=False
EndSub
'客户端反馈
PrivateSubWinsockSend_DataArrivalByValbytesTotalAsLong
DimcmdStrAsString
,vbString
IfMidcmdStr,1,13="NMSP_IAMREADY"Then'客户端已准备好接收时,要求客户端报告已经接收的文件大小
"NMSP_RPTCURLE"&filename
ElseIfMidcmdStr,1,13="NMSP_REQFILEN"Then'客户端要求发送文件名称
"NMSP_FILENAME="&filename
ElseIfMidcmdStr,1,13="NMSP_REQFILES"Then'客户端要求发送文件大小
"NMSP_FILESIZE="&filelength',vbLong
ElseIfMidcmdStr,1,13="NMSP_RECEIVED"Then'收到客户端已经接收到的文件大小报告
"客户端已经接收了"&MidcmdStr,14,LencmdStr
sendedData=MidcmdStr,15,LencmdStr
Iffilelength=sendedDataThen
"NMSP_SENDDONE"
'初始化文件名,大小,已接收大小,遍历是否还需要向别的客户端发送
Letfilename=""
Letfilelength=0
LetsendedData=0
="文件发送完毕"
Else
CallsendFile
EndIf
EndIf
EndSub
'==========================================================客户端======================================================
OptionExplicit
DimflagAsBoolean'设置是否继续接收文件的开关标识
PrivatereadyReceiveAsBoolean
PrivatefilenameAsString
PrivatetempfileAsString
PrivaterealfileAsString
PrivatereveivePathAsString
PrivatefilelengthAsLong'存储文件信息
PrivatedataAsByte,receivedAsLong'声明数据缓冲区和已接收的数据
PrivateSubForm_Load
reveivePath=&"received"
=sckTCPProtocol
=8080
CallinitReceiveState
EndSub
PrivateSubWinsockReceive_Connect
="已经连接到服务器"
EndSub
PrivateSubWinsockReceive_ConnectionRequestByValrequestIDAsLong
<>0Then
EndIf
="已接受连接请求;"
EndSub
PrivateSubWinsockReceive_DataArrivalByValbytesTotalAsLong
DimjAsLong
'分别接收传输文件的文件名、文件长度
',vbString,bytesTotal-4
',vbLong
'判断指令类型
IfreadyReceive=FalseThen
DimcmdStrAsString
,vbString
IfMidcmdStr,1,13="NMSP_AYUREADY"Then'询问是否准备好接收文件
Iffilename=""Then
"NMSP_REQFILEN"
ElseIffilelength=0Then
"NMSP_REQFILES"
Else
"NMSP_IAMREADY"
EndIf
ElseIfMidcmdStr,1,13="NMSP_FILENAME"Then'文件名
filename=MidcmdStr,15,LencmdStr
"NMSP_REQFILES"
ElseIfMidcmdStr,1,13="NMSP_FILESIZE"Then'文件大小
filelength=MidcmdStr,15,LencmdStr
Iffilelength<>0Then
"NMSP_IAMREADY"
EndIf
ElseIfMidcmdStr,1,13="NMSP_RPTCURLE"Then'服务器端要求提供已经接收的文件大小
'为传输文件设置临时文件
realfile=reveivePath&filename
tempfile=reveivePath&filename&".td"
'返回已接收的数据
'OpenrealfileForBinaryAs1
OpentempfileForBinaryAs2
IfLOF2>0Then
Input2,received
"received="&received
EndIf
Close2
"NMSP_RECEIVED="&received
readyReceive=True
="准备接收文件:"&filename&"大小为:"&filelength
ElseIfMidcmdStr,1,14="NMSP_SENDDONE="Then
'服务器发送文件完毕执行安装操作
EndIf
Else
realfile=reveivePath&filename
tempfile=reveivePath&filename&".td"
="正在接收文件:"&filename&"保存到:"&realfile
'返回已接收的数据
OpenrealfileForBinaryAs1
OpentempfileForBinaryAs2
'建立数据缓冲区
ReDimdatabytesTotal
'接收服务器端传输的数据
,vbArray+vbByte
'将接收的数据写入文件
Forj=received+1Toreceived+bytesTotal
Put1,j,dataj-received-1
Put2,j,dataj-received-1
Next
'更新已接收的数据
received=received+bytesTotal
'更新临时文件
'Write2,received
=Intreceived/filelength100
'传输完毕
>=100Then
="数据传输完毕"
Close2
'删除临时文件
Killtempfile
Close1
CallinitReceiveState
EndIf
Close1
Close2
EndIf
EndSub
PrivateSubinitReceiveState
readyReceive=False
received=0
filelength=0
filename=""
="监听中"
EndSub
版权声明:本文标题:VBSOCKET实现文件传输 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/dongtai/1706088584a170044.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论