这是发送端的代码:
    Dim myfile() As Byte
    Dim position As Long    Open "C:\1.bmp" For Binary As #1    position = 0    Do While Not EOF(1)
       position = position + 1
       ReDim Preserve myfile(1 To position)
       Get #1, , myfile(position)
    Loop    Close #1    sockserver.SendData myfile接受端代码:
Private Sub sockclient_DataArrival(ByVal bytestotal As Long)
   Dim i As Long
   Dim receiveFile() As Byte
   ReDim receiveFile(1 To bytestotal)
   sockclient.GetData receiveFile, vbArray + vbByte   Open "c:\A.BMP" For Binary As #1
   For i = 1 To bytestotal
      Put #1, , receiveFile
   Next i
    Close #1
End Sub但是这样子接受到的文件的大小变小了,我发现发送方一次发送过来数据,但是接受方会发生好几次DataArrival事件,怎么样把所有的数据都接受到呢?谢谢。

解决方案 »

  1.   

    这种方法完全错误
    重新写一个,不要用FOR循环来写,就算真要用FOR也别在DATAARRIVAL事件里用
      

  2.   

    啊,谢谢你了,是这样的,我是要做一个程序,用它来传输一些二进制的数据,最大是128K,所以我先写个程序来做个实验,看看用winsock控件来传输这些数据的方法,你能帮帮我吗?
      

  3.   

    做个缓冲,winsock收到的数据都加到缓冲中
    然后从其他的地方读缓冲的数据
      

  4.   

    估计你dataarrival事件的触发上有问题,文件如果比较大的话,要发送几次,不是一下子全都发过去的。
      

  5.   

    是的是的,确实是会发生好几次dataarrival事件,我受到的文件只是发过来的一部分,也就是说可能只收到其中一次的数据,那么怎么样才能收到所有的数据呢?
      

  6.   

    ÕâÊÇ·¢ËͶ˵ĴúÂë:
        Dim myfile() As Byte
        Dim position As Long    position = FileLen("C:\1.bmp")
        ReDim myfile(position - 1) As Byte
        
        Open "C:\1.bmp" For Binary As #1
           Get #1, 1, myfile
        Close #1    sockserver.SendData myfile½ÓÊܶ˴úÂë:
    Private Sub sockclient_DataArrival(ByVal bytestotal As Long)
       Dim i As Long
       Dim receiveFile() As Byte
       
       sockclient.GetData receiveFile   Open "c:\A.BMP" For Binary As #1
          Put #1, , receiveFile
       Close #1
    End Sub注意:你发送的文件不能太大!
    我还有个自己写的关于winsock的程序,后面补上
      

  7.   

    这是发送端的代码:
        Dim myfile() As Byte
        Dim position As Long    position = FileLen("C:\1.bmp")
        ReDim myfile(position - 1) As Byte
        
        Open "C:\1.bmp" For Binary As #1
           Get #1, 1, myfile
        Close #1    sockserver.SendData myfile接受端代码:
    Private Sub sockclient_DataArrival(ByVal bytestotal As Long)
       Dim i As Long
       Dim receiveFile() As Byte
       
       sockclient.GetData receiveFile   Open "c:\A.BMP" For Binary As #1
          Put #1, , receiveFile
       Close #1
    End Sub
      

  8.   

    '我自己的发送端函数:Public Sub SendFile(FileName As String, RemoteFilePath As String, WinS As Winsock, objProBar As ProgressBar)'FileName 是个本地需要发送的文件名(包含全路经)
    'RemoteFilePath 是个远端接收文件的地址(包含全路经,不包括文件名)
    'WinS是个Winsock对象,objProBar是个进度条对象
    'const SendDataSize =1024
    Dim FreeF As Integer
    Dim LenFile As Long
    Dim nCnt As Long
    Dim LocData() As Byte
    Dim Tempstr As String
    Dim a() As Byte
    Dim i As Long
    Dim myHead As StringFreeF = FreeFile
    Open FileName For Binary As FreeF    nCnt = 1
        LenFile = FileLen(FileName)
        
        Tempstr = IIf(Right$(RemoteFilePath, 1) = "\", RemoteFilePath & _
        Right$(FileName, Len(FileName) - InStrRev(FileName, "\")), RemoteFilePath & _
        "\" & Right$(FileName, Len(FileName) - InStrRev(FileName, "\")))
        
        myHead = "|FILESEND|" & Tempstr & "|" & CStr(LenFile)
        WinS.SendData myHead        '发送头和文件名及文件总长度!
        
        objProBar.Value = 0
        objProBar.Max = Fix(LenFile / SendDataSize) + 1
        objProBar.Visible = True
        
        Sleep (300)  '一个api函数
        
        Do Until nCnt > (LenFile)
            DoEvents
            If nCnt + SendDataSize - 1 > LenFile Then
                ReDim LocData(LenFile - nCnt) As Byte
            Else
                ReDim LocData(SendDataSize - 1) As Byte
            End If
            Get FreeF, nCnt, LocData 'Get data from the file nCnt is from where to start the get
        
            WinS.SendData LocData
        
            nCnt = nCnt + SendDataSize
        
            objProBar.Value = objProBar.Value + 1
        Loop
    Close FreeF
        objProBar.Value = objProBar.Max
        objProBar.Visible = False
    End Sub'我自己的接收端程序:Private Sub objTCP_DataArrival(Index As Integer, ByVal bytesTotal As Long) Dim strData As String
     Dim sData As String
     Dim lRet As Long
     Dim DataByte() As Byte
     
     objTCP(intmax).GetData DataByte
     
     strData = StrConv(DataByte, vbUnicode) 
        
         
    If Is_FILESEND = True Then                           'Is_FILESEND是个全局变量
        Put #myFreeFile, , DataByte
        SendFileLen = SendFileLen - UBound(DataByte) - 1
                
        If SendFileLen <= 0 Then
            Close #myFreeFile
            myFreeFile = 0
            Is_FILESEND = False
        End If
    Else
        If InStr(1, strData, "|FILESEND|") <> 0 Then
             Dim sFileName As String
             Dim k As Integer
             Is_FILESEND = True
             k = InStr(11, strData, "|")
             sFileName = Mid$(strData, 11, k - 11)
             SendFileLen = CLng(right$(strData, Len(strData) - k))
             myFreeFile = FreeFile
             Open sFileName For Binary As myFreeFile            
        End If    .........   '其他程序End If
      

  9.   

    TO:: Gelim(Gelim) 
    你前面给的两个代码和我自己的函数一样,都是只接受到了一部分,我把你的函数再瞧瞧。
      

  10.   

    用二进制来传可能会产生“截断”
    最好编码后在传,比如用base64编码就可以
      

  11.   

    第一个因为有汉字显示成乱码,怕误导人,所以传了第二个。第二个如果你的文件比较小,比如1k,不会有问题!至于第三个肯定没有问题,因为我的程序中就是这样用的!且测试成功!以上希望能帮到楼主!用base64编解码可能会费点写代码的时间,如果楼主需要,我可以贴出来!
      

  12.   

    当发送文件稍大时,就会产生几次dataArrival事件,而不是1次接收完毕
    你要从上次的位置接着写
      

  13.   

    Fengq(Fengq) 说的对,就是会发生好几次dataarrival事件,那么在写文件的时候就应该是追加,但是这样怎么做到呢?open 语句里的参数应该用什么呢?
         Gelim(Gelim)的程序我打印了带回去慢慢看。
        至于用base64编码后再传的办法,如果 Gelim(Gelim)不怕麻烦的话,烦劳你贴来给我瞧瞧,如果方便的话我改用这个办法传。
        这个月中旬就要我把项目做完,这个东西从这个月初才开始,小弟才疏学浅,光这个问题烦了我两天了,多谢各位的支持。
      

  14.   

    to null1027(营养不良的猪):我也不怕你说我,如果你一定要按你原来的方法可以这么写,在发送端除了发数据之外,再
    发这堆数据在原来文件中的偏移量(还可以加上校验字节),而接收端可以通过偏移量写到
    文件中,这样的话优点是很明显的,就是结构简单,逻辑清晰,还有就是数据不会出错,即
    使错了可以通过校验字节看出来后再要发送端再发一次,但这样却有个明显的缺点,那就是
    速度很慢,因为它要不停的写文件,而我给你的那种方法是先写到缓冲区,然后由close一次
    写到硬盘的,所以传输速度会很快!以下是base64的加解密算法:sBASE_64_CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    sBASE_64_CHARACTERS = strUnicode2Ansi(sBASE_64_CHARACTERS)Function strUnicodeLen(asContents)
    asContents1 = "a" & asContents
    len1 = Len(asContents1)
    k = 0
    For i = 1 To len1
    asc1 = Asc(Mid(asContents1, i, 1))
    If asc1 < 0 Then asc1 = 65536 + asc1
    If asc1 > 255 Then
    k = k + 2
    Else
    k = k + 1
    End If
    Next
    strUnicodeLen = k - 1
    End FunctionFunction strUnicode2Ansi(asContents)
    strUnicode2Ansi = ""
    len1 = Len(asContents)
    For i = 1 To len1
    VarChar = Mid(asContents, i, 1)
    varasc = Asc(VarChar)
    If varasc < 0 Then varasc = varasc + 65536
    If varasc > 255 Then
    varHex = Hex(varasc)
    varlow = Left(varHex, 2)
    varhigh = Right(varHex, 2)
    strUnicode2Ansi = strUnicode2Ansi & ChrB("&H" & varlow) & ChrB("&H" & varhigh)
    Else
    strUnicode2Ansi = strUnicode2Ansi & ChrB(varasc)
    End If
    Next
    End FunctionFunction strAnsi2Unicode(asContents)
    strAnsi2Unicode = ""
    len1 = LenB(asContents)
    If len1 = 0 Then Exit Function
    For i = 1 To len1
    VarChar = MidB(asContents, i, 1)
    varasc = AscB(VarChar)
    If varasc > 127 Then
    strAnsi2Unicode = strAnsi2Unicode & Chr(AscW(MidB(asContents, i + 1, 1) & VarChar))
    i = i + 1
    Else
    strAnsi2Unicode = strAnsi2Unicode & Chr(varasc)
    End If
    Next
    End FunctionFunction Base64encode(asContents)
    Dim lnPosition
    Dim lsResult
    Dim Char1
    Dim Char2
    Dim Char3
    Dim Char4
    Dim Byte1
    Dim Byte2
    Dim Byte3
    Dim SaveBits1
    Dim SaveBits2
    Dim lsGroupBinary
    Dim lsGroup64
    Dim M4, len1, len2len1 = LenB(asContents)
    If len1 < 1 Then
    Base64encode = ""
    Exit Function
    End IfM3 = len1 Mod 3
    If M3 > 0 Then asContents = asContents & String(3 - M3, ChrB(0))If M3 > 0 Then
    len1 = len1 + (3 - M3)
    len2 = len1 - 3
    Else
    len2 = len1
    End IflsResult = ""For lnPosition = 1 To len2 Step 3
    lsGroup64 = ""
    lsGroupBinary = MidB(asContents, lnPosition, 3)Byte1 = AscB(MidB(lsGroupBinary, 1, 1)): SaveBits1 = Byte1 And 3
    Byte2 = AscB(MidB(lsGroupBinary, 2, 1)): SaveBits2 = Byte2 And 15
    Byte3 = AscB(MidB(lsGroupBinary, 3, 1))Char1 = MidB(sBASE_64_CHARACTERS, ((Byte1 And 252) \ 4) + 1, 1)
    Char2 = MidB(sBASE_64_CHARACTERS, (((Byte2 And 240) \ 16) Or (SaveBits1 * 16) And &HFF) + 1, 1)
    Char3 = MidB(sBASE_64_CHARACTERS, (((Byte3 And 192) \ 64) Or (SaveBits2 * 4) And &HFF) + 1, 1)
    Char4 = MidB(sBASE_64_CHARACTERS, (Byte3 And 63) + 1, 1)
    lsGroup64 = Char1 & Char2 & Char3 & Char4lsResult = lsResult & lsGroup64
    NextIf M3 > 0 Then
    lsGroup64 = ""
    lsGroupBinary = MidB(asContents, len2 + 1, 3)Byte1 = AscB(MidB(lsGroupBinary, 1, 1)): SaveBits1 = Byte1 And 3
    Byte2 = AscB(MidB(lsGroupBinary, 2, 1)): SaveBits2 = Byte2 And 15
    Byte3 = AscB(MidB(lsGroupBinary, 3, 1))Char1 = MidB(sBASE_64_CHARACTERS, ((Byte1 And 252) \ 4) + 1, 1)
    Char2 = MidB(sBASE_64_CHARACTERS, (((Byte2 And 240) \ 16) Or (SaveBits1 * 16) And &HFF) + 1, 1)
    Char3 = MidB(sBASE_64_CHARACTERS, (((Byte3 And 192) \ 64) Or (SaveBits2 * 4) And &HFF) + 1, 1)If M3 = 1 Then
    lsGroup64 = Char1 & Char2 & ChrB(61) & ChrB(61) '&Oacute;&Atilde;=&ordm;&Aring;&sup2;&sup1;×&atilde;&Icirc;&raquo;&Ecirc;&yacute;
    Else
    lsGroup64 = Char1 & Char2 & Char3 & ChrB(61) '&Oacute;&Atilde;=&ordm;&Aring;&sup2;&sup1;×&atilde;&Icirc;&raquo;&Ecirc;&yacute;
    End IflsResult = lsResult & lsGroup64
    End IfBase64encode = lsResultEnd Function
    Function Base64decode(asContents)
    Dim lsResult
    Dim lnPosition
    Dim lsGroup64, lsGroupBinary
    Dim Char1, Char2, Char3, Char4
    Dim Byte1, Byte2, Byte3
    Dim M4, len1, len2len1 = LenB(asContents)
    M4 = len1 Mod 4If len1 < 1 Or M4 > 0 Then
    Base64decode = ""
    Exit Function
    End IfIf MidB(asContents, len1, 1) = ChrB(61) Then M4 = 3
    If MidB(asContents, len1 - 1, 1) = ChrB(61) Then M4 = 2If M4 = 0 Then
    len2 = len1
    Else
    len2 = len1 - 4
    End IfFor lnPosition = 1 To len2 Step 4
    lsGroupBinary = ""
    lsGroup64 = MidB(asContents, lnPosition, 4)
    Char1 = InStrB(sBASE_64_CHARACTERS, MidB(lsGroup64, 1, 1)) - 1
    Char2 = InStrB(sBASE_64_CHARACTERS, MidB(lsGroup64, 2, 1)) - 1
    Char3 = InStrB(sBASE_64_CHARACTERS, MidB(lsGroup64, 3, 1)) - 1
    Char4 = InStrB(sBASE_64_CHARACTERS, MidB(lsGroup64, 4, 1)) - 1
    Byte1 = ChrB(((Char2 And 48) \ 16) Or (Char1 * 4) And &HFF)
    Byte2 = lsGroupBinary & ChrB(((Char3 And 60) \ 4) Or (Char2 * 16) And &HFF)
    Byte3 = ChrB((((Char3 And 3) * 64) And &HFF) Or (Char4 And 63))
    lsGroupBinary = Byte1 & Byte2 & Byte3lsResult = lsResult & lsGroupBinary
    NextIf M4 > 0 Then
    lsGroupBinary = ""
    lsGroup64 = MidB(asContents, len2 + 1, M4) & ChrB(65) 'chr(65)=A&pound;&not;×&ordf;&raquo;&raquo;&sup3;&Eacute;&Ouml;&micro;&Icirc;&ordf;0
    If M4 = 2 Then '&sup2;&sup1;×&atilde;4&Icirc;&raquo;&pound;&not;&Ecirc;&Ccedil;&Icirc;&ordf;&Aacute;&Euml;±&atilde;&Oacute;&Uacute;&frac14;&AElig;&Euml;&atilde;
    lsGroup64 = lsGroup64 & ChrB(65)
    End If
    Char1 = InStrB(sBASE_64_CHARACTERS, MidB(lsGroup64, 1, 1)) - 1
    Char2 = InStrB(sBASE_64_CHARACTERS, MidB(lsGroup64, 2, 1)) - 1
    Char3 = InStrB(sBASE_64_CHARACTERS, MidB(lsGroup64, 3, 1)) - 1
    Char4 = InStrB(sBASE_64_CHARACTERS, MidB(lsGroup64, 4, 1)) - 1
    Byte1 = ChrB(((Char2 And 48) \ 16) Or (Char1 * 4) And &HFF)
    Byte2 = lsGroupBinary & ChrB(((Char3 And 60) \ 4) Or (Char2 * 16) And &HFF)
    Byte3 = ChrB((((Char3 And 3) * 64) And &HFF) Or (Char4 And 63))If M4 = 2 Then
    lsGroupBinary = Byte1
    ElseIf M4 = 3 Then
    lsGroupBinary = Byte1 & Byte2
    End IflsResult = lsResult & lsGroupBinary
    End IfBase64decode = lsResultEnd Function
      

  15.   

    TO Gelim(Gelim):呵呵,谢谢你的代码和意见,因为这个数据的传送端不是由我来写的,工期又很紧,也就只好先用这个办法了。
        通过你给的建议,我突然想出个新办法,定义一个静态变量,每次发生dataarrival事件的时候,都把收到的数据的大小加到这个变量上,然后在写文件的时候根据这个变量来判断写的位置,你觉得这样行不行?反正现在我还没调通,呵呵。
      

  16.   

    这样也好,不过你的速度会比较慢,而且会出错!如果发送端是别人写的,那他肯定会给你通讯协议的了,比如包头,数据包格式,是否存在加密啊等等信息!这样的话你可以用我的第三种方法,只是协议上要改,你肯定看出来我的包头是"|FILESEND|" ,你在那基础上改就好了!
      

  17.   

    to GetWindowPos(阿汪):1k左右的文件支持一次传送!但如果文件大就用第三种方法
      

  18.   

    在TCP里根本就没有GetWindowPos(阿汪) 所说的哪种问题,因为你发几次和发一次的效果是几乎一样的,底层是通过WindowsSize来控制的,我用VC做的视频传送一向都是几k几k一起发的,不过考虑到充分利用时间,不要让有的时间发的多,有的时间没发过,我才改为2k一次,不断循环
      

  19.   

    GetWindowPos(阿汪) 说得不对,你说的那种问题不存在,我做的视频传输就是几k几k传的。速度快得很,到底数据怎么发送是底层WindowSize决定的,不是你发几次,它就分几次发的,同样道理,我一次发几k,结果底层还是给我分成几个包来发
      

  20.   

    1、用TCP/IP方式是不会丢包的
    2、你要从发送到接收都按字节数组来进行,不要经过字符串转换
    3、用SockServe.BytesReceived检查缓存里有没有剩余的字节做到这三点就可以了,不用上面那么长的代码。我刚做完一个文件传输的程序,但鉴于其复杂度要高多了,所以代码不便贴出。
      

  21.   

    Gelim(Gelim) 的代码如下
    Open FileName For Binary As FreeF    nCnt = 1
        LenFile = FileLen(FileName)
        
        Tempstr = IIf(Right$(RemoteFilePath, 1) = "\", RemoteFilePath & _
        Right$(FileName, Len(FileName) - InStrRev(FileName, "\")), RemoteFilePath & _
        "\" & Right$(FileName, Len(FileName) - InStrRev(FileName, "\")))
        
        myHead = "|FILESEND|" & Tempstr & "|" & CStr(LenFile)
        WinS.SendData myHead        '发送头和文件名及文件总长度!
    ===================================================================
    这段代码明显就是把一个文件全部放到数组里然后一次过发送,这种方法我有什么可能没试过,没试过我敢说它慢吗?再来看看那个Greaitm(夜草) 说了些什么:我做的视频传输就是几k几k传的
    我想问问Greaitm(夜草),你知道我在说什么吗?你自己就不是这种方法的,你驳斥我什么啊?驳斥我不就是在驳斥你自己?请看我的回贴,我已说得清清楚楚:将一个文件一次过放到数组里发送,这种方法是最不可取的,不但吃资源,发送的时候传送速度每秒只有不到1K,还不能断点续传再来看看那个Greaitm(夜草) 说了些什么:我做的视频传输就是几k几k传的大家看看,可笑吗?最搞笑的是,那个 Gelim(Gelim)居然说什么:支持Greaitm(夜草)
    那么我又想问问了,Gelim(Gelim)你支持的人正好就是用了我的方法,而不是像你那样,你支持什么啊?支持个屁啊
      

  22.   

    to  GetWindowPos(阿汪):大家讨论技术没关系,但希望你能说话放干净点,大家都是程序员,用嘴说话的时间肯定比不过用手敲键盘!所以请你不要张嘴骂人!你说,我代码明显把一个文件全部放到数组里然后一次过发送,我真诚地希望你能好好看看我的程序,懂一点vb的人都知道我不是将整个文件放在数组里面,不信你可以将程序好好再往下看,myHead = "|FILESEND|" & Tempstr & "|" & CStr(LenFile)
    WinS.SendData myHead        '发送头和文件名及文件总长度!这两句话的意思是将数据包头"|FILESEND|" ,文件路径和文件的总长度发出去,而不是像你说的那样将整个文件发出去,大哥我的注释写得很清楚,就是不会vb的也看得出来再看:  
        Do Until nCnt > (LenFile)
            DoEvents
            If nCnt + SendDataSize - 1 > LenFile Then
                ReDim LocData(LenFile - nCnt) As Byte
            Else
                ReDim LocData(SendDataSize - 1) As Byte
            End If
            Get FreeF, nCnt, LocData    
            WinS.SendData LocData    
            nCnt = nCnt + SendDataSize   
            objProBar.Value = objProBar.Value + 1
        Loop上面这段代码才是将整个文件分成大小相等的包(长度LenFile=1024,最后一个包可能小于1024)也许,GetWindowPos(阿汪)大虾没有看清楚,这个我能理解,但至于我支持Greaitm(夜草)或者支持null1027 (营养不良的猪) 和你GetWindowPos(阿汪)有很大的关系吗?大家都是程序员,互相尊重很重要,我尊重你,也希望你能尊重我和你自己!to null1027 (营养不良的猪),我的email是[email protected],如果需要我们可以通过邮件联系!
      

  23.   

    对不起,上面的LenFile=1024笔误,应该是SendDataSize=1024。
      

  24.   

    to  GetWindowPos(阿汪):我本不想说什么,但是你说我没有试过将一个文件一次过放到数组里发送,我觉得奇怪,你又不是我你怎么知道?老实说我用winsock有一段时间了,如果你是这方面的专家,我佩服你,我向你学习,但是csdn牛人多得很,用单片机实现tcp/ip的都大有人在,呵呵!
      

  25.   

    两位,不要吵了好不好。
    我发的数据量比较小,并且是在局域网里,速度很快,60K的东西一秒内就可以收到,所以放到数组里一次传还是可行的,要大数据量的发送传输可以再问两位请教,但是吵架就不要了,因为我觉得好象你们二位讲的都是同样的道理,但是各自抓住自己的一方面在讲。
    另外非常感谢Gelim(Gelim) 的帮忙,解决了一个对我而言很严重的技术问题,呵呵,再有问题再找你了。
    谢谢。
      

  26.   

    讲的是同样的道理,但那个Gelim(Gelim)却好像只对人不对事,什么都要驳一下,既然是同样的道理他驳我干什么?这不是明摆着他想吵架吗?后来居然还说我骂他了,他以为社会上的人全是他娘呢,去到哪都会有人哄着他让着他,既然有人想吵架,我为什么不奉陪?