VBSOCKET实现文件传输_第1页
VBSOCKET实现文件传输_第2页
VBSOCKET实现文件传输_第3页
VBSOCKET实现文件传输_第4页
VBSOCKET实现文件传输_第5页
已阅读5页,还剩4页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

-.z.VB中使用WinSock控件传送文件传送文件对于网络编程来说是基本的功能,比如远程控制软件。在编制一个软件时,我从网上下了很多传文件的程序,这些程序提供的传文件功能根本就不能用。传文本还可以,传二进制文件根本就不行。因此,作为一个基本的功能模块,有必要单独介绍一下。首先,在VB中要传送字符串,你可以这样写:

DimstrDataAsString

strData="Test"

Winsock1.SendDatastrData

但是如果你传送的二进制文件,你还能用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'关闭文件

WinS.SendDatabytData'发送数据

EndSub

接受端的程序如下:

PrivateSubWinsock1_DataArrival(ByValbytesTotalAsLong)

DimbytData()AsByte

Dimf

f=FreeFile

OpenstrFileNameForBinaryAs*f

ReDimbytData(1TobytesTotal)

Winsock1.GetDatabytData

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。这个变量保存着当前数据的位置。ConstiMa*=65535是每个数据块的大小。

dimiposaslong

ConstiMa*=65535

DimFreeFAsInteger'空闲的文件号

DimLenFileAsLong'文件的长度

DimbytData()AsByte'存放数据的数组

FreeF=FreeFile'获得空闲的文件号

OpenFileNameForBinaryAs*FreeF'打开文件

DoEvents

LenFile=LOF(FreeF)'获得文件长度

IfLenFile<=iMa*Then'如果要发送的文件小于数据块大小,直接发送

ReDimbytData(1ToLenFile)'根据文件长度重新定义数组大小

Get*FreeF,,bytData'把文件读入到数组里

Close*FreeF'关闭文件

WinS.SendDatabytData'发送数据

E*itSub

EndIf

'文件大于数据块大小,进行分块发送

DoUntil(iPos>=(LenFile-iMa*))'发送整块数据的循环

ReDimbytData(1ToiMa*)

Get*FreeF,iPos+1,bytData

WinS.SendDatabytData

iPos=iPos+iMa*'移动iPos,使它指向下来要读的数据

Loop

'这里要注意的是,必须检查文件有没有剩下的数据,如果文件大小正好等于数据块大小的

'整数倍,则就没有剩下的数据了

ReDimbytData(1ToLenFile-iPos)'发送剩下的不够一个数据块的数据

Get*FreeF,iPos+1,bytData

WinS.SendDatabytData

Close*FreeF

下面是接收端的程序:

PrivateSubWinsock1_DataArrival(ByValbytesTotalAsLong)

DimbytData()AsByte

DimlLenFileAsLong

Dimf

f=FreeFile

OpenstrFileNameForBinaryAs*f'strFileName是文件名

lLenFile=LOF(f)

ReDimbytData(1TobytesTotal)

Winsock1.GetDatabytData

IflLenFile=0Then'lLenFile=0表示是第一次打开文件,这里有个问题,就是'如果如果该文件存在的话,就会出错,应该在打开前检查文件是否存在。(这里我省略了)

Put*f,1,bytData

Else

Put*f,lLenFile+1,bytData

EndIf

Close*f

EndSubVBSOCKET实现文件传输支持断点续传OptionE*plicitConstPACKSIZEAsLong=65536'每包大小为64KPrivatefilepathAsStringPrivatefilenameAsStringPrivatefilelengthAsLong'存储文件信息Privatedata()AsBytePrivatepackAsLongPrivatesendedDataAsLong'数据缓冲区,文件包数,已传输的数据PrivatealreadySendAsBooleanPrivatecmsStrAsStringConstfileDAsString="D:\NMSPlugin\source\LanBus.rar"PrivateSubcmdConnectClient_Click()WinsockSend.CloseWinsockSend.Protocol=sckTCPProtocolWinsockSend.RemoteHost=""WinsockSend.RemotePort=8080WinsockSend.Connect'连接客户端EndSubPrivateSubcmdSendFile_Click()OpenfileDForBinaryAs*3filename="LanBus.rar"filelength=LOF(3)Close*3WinsockSend.SendData("NMSP_AYUREADY")EndSubPrivateSubWinsockSend_Connect()StatusBar1.Caption="已与客户端建立连接。"EndSub'"发送文件"按钮事件代码:PrivateSubsendFile()DimiAsIntegerDimjAsLongDimmAsLongfilepath=fileDStatusBar1.Caption="向客户端传送文件:"&filename&"大小为:"&filelength'计算需要传输文件的包数pack=(filelength-sendedData)\PACKSIZEIf((filelength-sendedData)ModPACKSIZE)<>0Thenpack=pack+1EndIfIfpack=0Thenpack=pack+1EndIf'传输文件OpenfilepathForBinaryAs*1Fori=1Topack'如果只有一包Ifpack=1ThenDebug.Print"filename="&filename&"|filelength="&filelength&"|send="&sendedDataReDimdata(filelength-sendedData)'读取数据Forj=sendedData+1TofilelengthGet*1,j,data(j-sendedData)Ne*t'更新已传输文件的数据sendedData=filelength'发送文件数据WinsockSend.SendDatadata'如果是最后一包ElseIfi+1=packThen'读取最后一包的数据ReDimdata(filelength-sendedData)Forj=1Tofilelength-sendedDataGet*1,sendedData+j,data(j)Ne*t'发送文件数据WinsockSend.SendDatadata'更新已传输文件的数据sendedData=filelengthE*itForElse'将文件数据放到数据缓冲区ReDimdata(PACKSIZE)Form=1ToPACKSIZEGet*1,sendedData+m,data(j)Ne*t'发送文件数据WinsockSend.SendDatadata'更新已传输文件的数据sendedData=sendedData+PACKSIZEEndIfProgressBar1.Value=Int((sendedData/filelength)*100)Ne*tProgressBar1.Value=Int((sendedData/filelength)*100)Close*1alreadySend=FalseEndSub'客户端反馈PrivateSubWinsockSend_DataArrival(ByValbytesTotalAsLong)DimcmdStrAsStringWinsockSend.GetDatacmdStr,vbStringDebug.PrintcmdStrIfMid(cmdStr,1,13)="NMSP_IAMREADY"Then'客户端已准备好接收时,要求客户端报告已经接收的文件大小WinsockSend.SendData"NMSP_RPTCURLE"&filenameElseIfMid(cmdStr,1,13)="NMSP_REQFILEN"Then'客户端要求发送文件名称WinsockSend.SendData"NMSP_FILENAME="&filenameElseIfMid(cmdStr,1,13)="NMSP_REQFILES"Then'客户端要求发送文件大小WinsockSend.SendData"NMSP_FILESIZE="&filelength'WinsockSend.GetDatasend,vbLongElseIfMid(cmdStr,1,13)="NMSP_RECEIVED"Then'收到客户端已经接收到的文件大小报告Debug.Print"客户端已经接收了"&Mid(cmdStr,14,Len(cmdStr))sendedData=Mid(cmdStr,15,Len(cmdStr))Iffilelength=sendedDataThenWinsockSend.SendData"NMSP_SENDDONE"'初始化文件名,大小,已接收大小,遍历是否还需要向别的客户端发送Letfilename=""Letfilelength=0LetsendedData=0WinsockSend.CloseStatusBar1.Caption="文件发送完毕!"ElseCallsendFileEndIfEndIfEndSub'==========================================================客户端======================================================OptionE*plicitDimflagAsBoolean'设置是否继续接收文件的开关标识PrivatereadyReceiveAsBooleanPrivatefilenameAsStringPrivatetempfileAsStringPrivaterealfileAsStringPrivatereveivePathAsStringPrivatefilelengthAsLong'存储文件信息Privatedata()AsByte,receivedAsLong'声明数据缓冲区和已接收的数据PrivateSubForm_Load()reveivePath=App.Path&"\received\"WinsockReceive.Protocol=sckTCPProtocolWinsockReceive.LocalPort=8080WinsockReceive.ListenCallinitReceiveStateEndSubPrivateSubWinsockReceive_Connect()StatusBar1.Caption="已经连接到服务器"EndSubPrivateSubWinsockReceive_ConnectionRequest(ByValrequestIDAsLong)IfWinsockReceive.State<>0ThenWinsockReceive.CloseEndIfWinsockReceive.AcceptrequestIDStatusBar1.Caption="已接受连接请求。"EndSubPrivateSubWinsockReceive_DataArrival(ByValbytesTotalAsLong)DimjAsLong'分别接收传输文件的文件名、文件长度'WinsockReceive.GetDatafilename,vbString,bytesTotal-4'WinsockReceive.GetDatafilelength,vbLong'判断指令类型IfreadyReceive=FalseThenDimcmdStrAsStringWinsockReceive.GetDatacmdStr,vbStringDebug.PrintcmdStrIfMid(cmdStr,1,13)="NMSP_AYUREADY"Then'询问是否准备好接收文件Iffilename=""ThenWinsockReceive.SendData("NMSP_REQFILEN")ElseIffilelength=0ThenWinsockReceive.SendData("NMSP_REQFILES")ElseWinsockReceive.SendData("NMSP_IAMREADY")EndIfElseIfMid(cmdStr,1,13)="NMSP_FILENAME"Then'文件名filename=Mid(cmdStr,15,Len(cmdStr))WinsockReceive.SendData("NMSP_REQFILES")ElseIfMid(cmdStr,1,13)="NMSP_FILESIZE"Then'文件大小filelength=Mid(cmdStr,15,Len(cmdStr))Debug.PrintfilelengthIf(filelength<>0)ThenWinsockReceive.SendData("NMSP_IAMREADY")EndIfElseIfMid(cmdStr,1,13)="NMSP_RPTCURLE"Then'服务器端要求提供已经接收的文件大小'为传输文件设置临时文件realfile=reveivePath&filenametempfile=reveivePath&filename&".td"'返回已接收的数据'OpenrealfileForBinaryAs*1OpentempfileForBinaryAs*2IfLOF(2)>0ThenInput*2,receivedDebug.Print"received="&receivedEndIfClose*2WinsockReceive.SendData"NMSP_RECEIVED="&receivedreadyReceive=TrueStatusBar1.Caption="准备接收文件:"&filename&"大小为:"&filelengthElseIfMid(cmdStr,1,14)="NMSP_SENDDONE="Then'服务器发送文件完毕执行安装操作EndIfElserealfile=reveivePath&filenametempfile=reveivePath&filename&".

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论