none
socket.receive接收資料 但大小不確定 RRS feed

  • 問題

  •  

    dim bytes(1024)  as byte

    socket.receive(bytes)

    這樣接收檔案大小會是1024byte

    但是如果更小怎麼辦或是更大

    接收的檔案大小不確定  該怎麼設定bytes 

    我設定過bytes(20000) as byte

    這樣就算接收1KB檔案也會變成20KB

    這該怎麼設定??

    2007年7月27日 上午 03:23

解答

  • 那個連結按下去只 3 ~ 4 篇,扣去沒有程式碼的,有一篇有完整程式碼包含註解:

     

    Private Function GetReturnBytes(Optional ByVal bMultiLine As Boolean = False) As Byte()
      Dim allBytes, nBytes As Integer
      Dim bExit As Boolean = False
      Dim eDate As Date = DateTime.Now.AddMilliseconds(m_TimeOut)
      Dim rtnBytes As Byte()
      Dim nBuffer As Integer = m_TcpClient.ReceiveBufferSize
      Dim tBytes(m_TcpClient.ReceiveBufferSize - 1) As Byte

      allBytes = -1
      ReDim rtnBytes(allBytes)
      Do
       Try ' 試試看網路有沒有抓到資料,記住,所有資料不會一口氣全進來,所以要慢慢等。
        nBytes = m_NetworkStream.Read(tBytes, 0, nBuffer)
       Catch
        nBytes = 0
       End Try
       If nBytes > 0 Then
        allBytes += nBytes
        ReDim Preserve rtnBytes(allBytes)
        Array.Copy(tBytes, 0, rtnBytes, allBytes - nBytes + 1, nBytes) ' 陣列相加
       End If
       System.Threading.Thread.Sleep(0) ' 讓執行緒睡一下,來等新資料從網路進來,也把 CPU 資源放出來,ASP.NET 沒有 Application.DoEvents 可用,只能這樣放 CPU 出來。
       If m_NetworkStream.DataAvailable Then
        eDate = DateTime.Now.AddMilliseconds(m_TimeOut)
       Else
        If allBytes > 1 Then
         If bMultiLine Then ' 多行處理
          ... (bExit = True)
         Else
          ... (bExit = True)      
         End If
        End If
       End If
       If DateTime.Now > eDate Then ' 逾時處理
        bExit = True
       End If
      Loop Until bExit
      Return rtnBytes
     End Function

     

     

    關鍵字給了,可以用 IE 的尋找來找尋,連結給了,不過就幾篇文章還找不到,我實在不知道該怎樣說了。
    2007年7月29日 下午 02:37
    版主

所有回覆

  • dim bytes(200000) as byte

    這樣接收的話檔案會變成20mb也會損毀 因為太大了

    有神麼方法可以把byte調成跟要接收的檔案大小剛剛好 不會損毀

    2007年7月27日 上午 04:53
  • Dear Sir

    您用Receive方法時應該會回傳一個integer,表示實際收到的byte數量,其餘多出來的都是無效資料,應該都會是0;所以可以利用回傳的integer去處理相關動作,參考看看。

    2007年7月27日 上午 05:10
    版主
  • 請自己做 Byte 接收與合併到新的陣列去。

    我印象中 Tcp 的 Buffer 區只有 8 kb ,你設再大也沒用。

     

    自訂傳輸最好先送位元組數,再來檢查與判斷總數。先前 TcpClient 的相關討論也有類似原始碼。

     

    請搜尋:

    TcpClient MemoryStream

    2007年7月27日 上午 07:09
    版主
  • 所以說Tcp最多只能傳8KB的檔案??



    2007年7月27日 下午 02:15
  • Buffer 翻成中文叫做緩衝區。

     

    假設你負責要把東西從 A 倉庫搬到 B 倉庫,比如說總重量 1,000 公斤好了,你舉重能力為 50 公斤,這 50 公斤就是緩衝區。

     

    你能不能搬 1,000 公斤的東西?很顯然,一次不行,所以要分次搬。

     

    所以說,Tcp 最多能傳多大的檔案?基本上沒上限,但是要分次送,所以會有封包,一個封包就是一次。一般來說,寬頻的封包每個 1500 bytes ,撥接式每個封包 512 bytes ,由於封包會包含額外的資訊,來源位置、目標位置,所以傳輸時會有額外的流量在浪費,另外還有交談的內容在浪費流量。這部份基本上是包裝好自動處理的,所以原則上不用管太多。

     

    好現在假定你要傳遞 100 mb 的檔案,發送端直接寫入 socket ,剩下的作業系統會幫你處理,但是接收呢?假定每秒你可以收到 2kb ,所以要 50000 秒,你程式可能在第 0 秒就讀取到所有資料嗎?顯然不行,你可以等到第 50000 秒在讀取 100 mb 嗎?由於 Buffer 的限制,也不行,所以你必須隨時去把緩衝區內的資料讀出來,不管是寫入檔案也好,寫入記憶體也好,這部份必須開發者去處理,太密集讀取緩衝區,吃系統資源,太久才處理,會因為緩衝區滿了,造成傳輸暫停,整體傳輸速度降低,所以你必須拿捏這個空檔跟密度。

     

    在線上手冊關於 Socket.SendBufferSize, Socket.ReceiveBufferSize 的說明有寫:

    屬性值
    Int32,包含傳送緩衝區的大小 (以位元組為單位)。預設值8192

    備註
    較大的緩衝區大小可能會延遲連線困難的辨識。如果您正在傳送大型檔案,或是在使用高頻寬、高延遲連接 (例如人造衛星寬頻提供者) 時,請考慮增加緩衝區大小。

     

    而 Socket.Receive 方法 的說明有寫:

    傳回值
    接收的位元組數目。

     

    所以你的 Byte() 雖然是你宣告的大小,但是你只要處理 0 ~ 傳回值 - 1 的內容。

     

    更多的細節,請參考線上手冊相關說明。迴圈處理與時間延遲,請搜尋既有討論。

    • 已提議為解答 平oscar 2011年4月30日 上午 03:48
    • 已取消提議為解答 平oscar 2011年4月30日 上午 03:48
    2007年7月27日 下午 03:24
    版主
  • 喔喔所以說

    發送端只需要

    dim bytes(這邊設定的根檔案一樣大) as byte

    socket.send(bytes)

    ''''''''''''''---------------------------------------

    然後接收端

    只要把byte設定8kb

    然後再多次傳送

    請問大大要怎麼寫多次接收阿

    是這樣嗎

    dim bytes(8192){這樣是最大??} as byte

    dim receivebyte() AS byte

    if bytes <  receivebyte then

    socket.receive(bytes)

    receivebyte = bytes

    end if

    是這樣嗎

    之後收到的就是receivebyte嗎

     

     

    2007年7月28日 上午 06:21
  • 嗯恩

    傳送端可以用sendfile
    一次傳整個檔案
    接收端 分開來接收

    然後
    接收端''''''''''''''''''''''''''''''''''''''''''''
            Dim socket As System.Net.Sockets.Socket

            Dim bytes(socket.ReceiveBufferSize) As Byte

            socket.Receive(bytes)
    這樣子設定byte  ok吧
    2007年7月28日 上午 11:55
  • 請把後面迴圈接收也看一遍。

     

    2007年7月28日 下午 02:43
    版主
  • 哪裡?? msdn的嗎??

     

    2007年7月29日 上午 08:59
  • 2007年7月29日 下午 02:00
    版主
  •         Dim numberOfBytesRead As Integer
            Dim myReadBuffer(4096) As Byte
            Dim myCompleteMessage As StringBuilder = New StringBuilder

            Do
                numberOfBytesRead = stream.Read(myReadBuffer, 0, myReadBuffer.Length)
                myCompleteMessage.AppendFormat("{0}", Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead))
            Loop While stream.DataAvailable


    是這段嗎


          Dim myCompleteMessage As StringBuilder = New StringBuilder

    要把StringBuilder  改成byte來接收嗎


    2007年7月29日 下午 02:27
  • 那個連結按下去只 3 ~ 4 篇,扣去沒有程式碼的,有一篇有完整程式碼包含註解:

     

    Private Function GetReturnBytes(Optional ByVal bMultiLine As Boolean = False) As Byte()
      Dim allBytes, nBytes As Integer
      Dim bExit As Boolean = False
      Dim eDate As Date = DateTime.Now.AddMilliseconds(m_TimeOut)
      Dim rtnBytes As Byte()
      Dim nBuffer As Integer = m_TcpClient.ReceiveBufferSize
      Dim tBytes(m_TcpClient.ReceiveBufferSize - 1) As Byte

      allBytes = -1
      ReDim rtnBytes(allBytes)
      Do
       Try ' 試試看網路有沒有抓到資料,記住,所有資料不會一口氣全進來,所以要慢慢等。
        nBytes = m_NetworkStream.Read(tBytes, 0, nBuffer)
       Catch
        nBytes = 0
       End Try
       If nBytes > 0 Then
        allBytes += nBytes
        ReDim Preserve rtnBytes(allBytes)
        Array.Copy(tBytes, 0, rtnBytes, allBytes - nBytes + 1, nBytes) ' 陣列相加
       End If
       System.Threading.Thread.Sleep(0) ' 讓執行緒睡一下,來等新資料從網路進來,也把 CPU 資源放出來,ASP.NET 沒有 Application.DoEvents 可用,只能這樣放 CPU 出來。
       If m_NetworkStream.DataAvailable Then
        eDate = DateTime.Now.AddMilliseconds(m_TimeOut)
       Else
        If allBytes > 1 Then
         If bMultiLine Then ' 多行處理
          ... (bExit = True)
         Else
          ... (bExit = True)      
         End If
        End If
       End If
       If DateTime.Now > eDate Then ' 逾時處理
        bExit = True
       End If
      Loop Until bExit
      Return rtnBytes
     End Function

     

     

    關鍵字給了,可以用 IE 的尋找來找尋,連結給了,不過就幾篇文章還找不到,我實在不知道該怎樣說了。
    2007年7月29日 下午 02:37
    版主
  • 這個我也有看到的說...= =

    我知道了
    Array.Copy(tBytes, 0, rtnBytes, allBytes - nBytes + 1, nBytes)
    陣列相加 

    是哪個加到哪個鴨?





    2007年7月29日 下午 03:42
  • 請看線上手冊 Array.Copy 的說明。

    2007年7月29日 下午 03:51
    版主
  • 我剛剛用程式裡的物件瀏覽器看了
    第一個就是要複製到的
    第二個就是從哪裡開始複製
    第三個就是接收的
    第四個就是從哪裡開始加進來
    第五個就是加多少位元組
    是這樣嗎


    2007年7月29日 下午 04:15
  • 線上手冊不等於物件瀏覽器。不要跟我雞同鴨講。

     

    ms-help://MS.MSDNQTR.v80.cht/MS.MSDN.v80/MS.NETDEVFX.v20.cht/cpref7/html/M_System_Array_Copy_2_9679b07d.htm

    Array.Copy 方法 (Array, Int32, Array, Int32, Int32)

    Visual Basic (宣告)

    Public Shared Sub Copy ( _ 
    sourceArray As Array, _ 
    sourceIndex As Integer, _ 
    destinationArray As Array, _ 
    destinationIndex As Integer, _ 
    length As Integer _
    )

    Visual Basic (使用方式)

    Dim sourceArray As Array
    Dim
    sourceIndex As Integer
    Dim destinationArray As Array
    Dim
    destinationIndex As Integer
    Dim
    length As Integer
    Array.Copy(sourceArray, sourceIndex, destinationArray, destinationIndex, length)

    參數

    sourceArray

    包含要複製資料的 Array

    sourceIndex

    32 位元的整數,代表 sourceArray 中的索引,由此開始複製。

    destinationArray

    接收資料的 Array

    destinationIndex

    32 位元的整數,代表 destinationArray 中的索引,由此開始儲存。

    length

    32 位元整數,表示要複製的元素數目。

     

     

     

    2007年7月30日 上午 01:32
    版主
  • 我寫的程式碼好像怪怪的

    好像有錯

    Dim b() As Byte = GetReturnBytes(False)

     

    Private Function GetReturnBytes(Optional ByVal bMultiLine As Boolean = False) As Byte()
      Dim allBytes, nBytes As Integer
      Dim bExit As Boolean = False
      Dim eDate As Date = DateTime.Now.AddMilliseconds(m_TimeOut)'這要設定成多少??
      Dim rtnBytes As Byte()
      Dim nBuffer As Integer = m_TcpClient.ReceiveBufferSize
      Dim tBytes(m_TcpClient.ReceiveBufferSize - 1) As Byte

      allBytes = -1
      ReDim rtnBytes(allBytes)
      Do
       Try ' 試試看網路有沒有抓到資料,記住,所有資料不會一口氣全進來,所以要慢慢等。
        nBytes = m_NetworkStream.Read(tBytes, 0, nBuffer)
       Catch
        nBytes = 0
       End Try
       If nBytes > 0 Then
        allBytes += nBytes
        ReDim Preserve rtnBytes(allBytes)
        Array.Copy(tBytes, 0, rtnBytes, allBytes - nBytes + 1, nBytes) ' 陣列相加
       End If
       System.Threading.Thread.Sleep(0) ' 讓執行緒睡一下,來等新資料從網路進來,也把 CPU 資源放出來,ASP.NET 沒有 Application.DoEvents 可用,只能這樣放 CPU 出來。
       If m_NetworkStream.DataAvailable Then
        eDate = DateTime.Now.AddMilliseconds(m_TimeOut)  '這個該設定成多少呢
       Else
        If allBytes > 1 Then
         If bMultiLine Then ' 多行處理  這邊是幹嘛的
          bExit = True   '這邊...要寫成神麼呢  我這樣寫對嗎
         Else
          bExit = True   '這邊也是一樣  
         End If
        End If
       End If
       If DateTime.Now > eDate Then ' 逾時處理
        bExit = True
       End If
      Loop Until bExit
      Return rtnBytes
     End Function

     

    謝謝了

    2007年7月30日 下午 02:17
  • m_TimeOut 是連線逾時,你認為多久沒回應該視為斷線,就用那個值。

     

    這是 NNTP/POP3 協定的一部份,是最後的完結字元組,請用你自訂的通訊協定方式替換,細節請配合來源那篇的討論。

    2007年7月30日 下午 03:34
    版主
  • 喔喔原來 逾時就是這個喔

    我剛剛有回去看那偏討論
    http://forums.microsoft.com/msdn-cht/ShowPost.aspx?PostID=585942&SiteID=14
    還是看不懂
    我想說
    我能不能直接把最後面的回圈接收 改成
    loop while stream.DataAvailable
    就變成這樣
    Private Function GetReturnBytes(Optional ByVal bMultiLine As Boolean = False) As Byte()
      Dim allBytes, nBytes As Integer
      Dim rtnBytes As Byte()
      Dim nBuffer As Integer = m_TcpClient.ReceiveBufferSize
      Dim tBytes(m_TcpClient.ReceiveBufferSize - 1) As Byte
      allBytes = -1
      ReDim rtnBytes(allBytes)
      Do
       Try ' 試試看網路有沒有抓到資料,記住,所有資料不會一口氣全進來,所以要慢慢等。
        nBytes = m_NetworkStream.Read(tBytes, 0, nBuffer)
       Catch
        nBytes = 0
       End Try
       If nBytes > 0 Then
        allBytes += nBytes
        ReDim Preserve rtnBytes(allBytes)
        Array.Copy(tBytes, 0, rtnBytes, allBytes - nBytes + 1, nBytes) ' 陣列相加
       End If
      Loop while stream.DataAvailable
      Return rtnBytes
     End Function

    這樣行嗎
    因為我實在搞不懂多行處理
    謝謝璉璉大大

    2007年7月31日 上午 02:43
  • 前面一直跟你強調網路傳輸需要時間,你好像還是沒搞懂。

     

    DataAvailable 是目前資料流是否有可用資料。

     

    這個跟你取資料的頻率以及網路狀況有關,若是你取資料的瞬間剛好沒資料,不代表下 0.01 秒就沒資料進來,所以原先程式碼只用來判斷是否要讀取,並不用來判斷是否結束。

     

    結束的條件,視你的通訊協定定義的來處理,再加上逾時作為例外條件,不是用這個。

    2007年7月31日 上午 02:54
    版主
  • 喔喔
    那我設定逾時
    imports system.net.sockets
    Private Function GetReturnBytes(Optional ByVal bMultiLine As Boolean = False) As Byte()
      Dim allBytes, nBytes As Integer
      Dim rtnBytes As Byte()
      Dim nBuffer As Integer = m_TcpClient.ReceiveBufferSize
      Dim tBytes(m_TcpClient.ReceiveBufferSize - 1) As Byte
    dim exit as boolean =false
      m_TcpClient.ReceiveTimeout = 5000  '設定逾時五秒
      allBytes = -1
      ReDim rtnBytes(allBytes)
      Do
       Try ' 試試看網路有沒有抓到資料,記住,所有資料不會一口氣全進來,所以要慢慢等。
        nBytes = m_NetworkStream.Read(tBytes, 0, nBuffer)
            Catch ex as SocketException  'http://msdn2.microsoft.com/zh-tw/library/8s4y8aff(VS.80).aspx說這是逾時的例外
                   exit =true
           Catch 
                   nBytes = 0
       End Try
       If nBytes > 0 Then
        allBytes += nBytes
        ReDim Preserve rtnBytes(allBytes)
        Array.Copy(tBytes, 0, rtnBytes, allBytes - nBytes + 1, nBytes) ' 陣列相加
       End If
      Loop Until exit
      Return rtnBytes
     End Function

    這樣改ok嗎

    2007年7月31日 上午 03:16
  • 這樣設定之後就沒有反映了??

    是我逾時調太高嗎??

       Try ' 試試看網路有沒有抓到資料,記住,所有資料不會一口氣全進來,所以要慢慢等。
        nBytes = m_NetworkStream.Read(tBytes, 0, nBuffer)
       Catch
        nBytes = 0
       End Try

     

     

    請問第三行跟第四行是神麼阿

    catch後面沒有東西  ??

    不是應該要這樣??

    Catch ex As Exception

    2007年8月2日 下午 06:50
  • 所有的錯誤都到這行。

     

    2007年8月3日 上午 07:12
    版主