zoukankan      html  css  js  c++  java
  • 使用Net.Sockets.TcpListener和Net.Sockets.TcpClient进行图片传输时怎样精确控制接收缓存数组大小

    <span style="font-size:18px;">在dotnet平台Net.Sockets.TcpListener和Net.Sockets.TcpClient已经为我们封装了全部Socket关于tcp部分,操作也更为简单,面向数据流。使用TcpClient的GetStream方法获取数据流后能够方便的对数据流进行读写操作,就如同本地磁盘的文件读写一样,使得程序猿在设计程序时更为便捷简单。</span>

    但假设你使用过这两个对象进行传输数据的时候,你会发现问题也随之而来——GetStream获取的数据流是一个永无止境的Stream,你无法获取它的详细长度。

    来看一下微软MSDN关于这两个对象的例程:

    Shared Sub Connect(server As [String], message As [String])
       Try
          ' Create a TcpClient.
          ' Note, for this client to work you need to have a TcpServer 
          ' connected to the same address as specified by the server, port
          ' combination.
          Dim port As Int32 = 13000
          Dim client As New TcpClient(server, port)
    
          ' Translate the passed message into ASCII and store it as a Byte array.
          Dim data As [Byte]() = System.Text.Encoding.ASCII.GetBytes(message)
    
          ' Get a client stream for reading and writing.
          '  Stream stream = client.GetStream();
          Dim stream As NetworkStream = client.GetStream()
    
          ' Send the message to the connected TcpServer. 
          stream.Write(data, 0, data.Length)
    
          Console.WriteLine("Sent: {0}", message)
    
          ' Receive the TcpServer.response.
          ' Buffer to store the response bytes.
          data = New [Byte](256) {}
    
          ' String to store the response ASCII representation.
          Dim responseData As [String] = [String].Empty
    
          ' Read the first batch of the TcpServer response bytes.
          Dim bytes As Int32 = stream.Read(data, 0, data.Length)
          responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes)
          Console.WriteLine("Received: {0}", responseData)
    
          ' Close everything.
          stream.Close()
          client.Close()
       Catch e As ArgumentNullException
          Console.WriteLine("ArgumentNullException: {0}", e)
       Catch e As SocketException
          Console.WriteLine("SocketException: {0}", e)
       End Try
    
       Console.WriteLine(ControlChars.Cr + " Press Enter to continue...")
       Console.Read()
    End Sub 'Connect
    你不得不去指定一个固定尺寸的缓冲区来接收数据,假设实际发送的数据超出了这个长度,你可能无法接收到所有完整的数据,而假设发送的数据少于缓冲区的大小,那么非常显然你的内存会比别人消耗的更快。更为严重的时。假设你要发送一副图片,图片容量可能依据内容的不同而各有千秋,容量也不止256Byte这么小,该怎样精确控制缓冲区呢?


    事实上我们能够非常easy的解决问题,就像非常多文件格式所做的事情一样,我们能够在Stream的前几个字节写入实际有效数据的长度。然后依据这个长度来分配内存。再读取内容,我所做的client与server之间传递屏幕的源码例如以下:


    '----------------client----------------

    <pre name="code" class="vb">Public Class Form1
    
    
        Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
            Dim tcpc As New Net.Sockets.TcpClient
            Dim slens(7) As Byte
            Try
                tcpc.Connect("127.0.0.1", 2099)
                If tcpc.Connected Then
                    For i = 0 To 7
                        slens(i) = tcpc.GetStream.ReadByte
                    Next
    
                    Dim buf(BitConverter.ToUInt64(slens, 0)) As Byte
                    Me.Text = buf.Length
                    tcpc.GetStream.Read(buf, 0, buf.Length)
                    Dim mem As New IO.MemoryStream(buf)
                    Dim bmp As New Bitmap(mem)
                    Me.PictureBox1.Image = bmp
                    tcpc.Close()
                End If
            Catch ex As Exception
    
            Finally
                tcpc.Close()
            End Try
        End Sub
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    
        End Sub
    End Class
    

    
    

    
    '------------server----------------
    

    Public Class Form1
    
        Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
            Dim tcps As New Net.Sockets.TcpListener(2099)
            tcps.Start()
            While True
                Dim slen As UInt64
                Dim slens(7) As Byte
                Dim tcpc As Net.Sockets.TcpClient
                tcpc = tcps.AcceptTcpClient
    
                '创建图片
                Dim bmp As New Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height)
                bmp.SetResolution(1, 1)
    
    
    
                Dim gph As Graphics = Graphics.FromImage(bmp)
                gph.CopyFromScreen(New Point(0, 0), New Point(0, 0), bmp.Size)
                gph.Flush()
    
                '存入内存
                Dim mem As New IO.MemoryStream
                bmp.Save(mem, Drawing.Imaging.ImageFormat.Tiff)
    
    
                '文件长度
                slen = mem.Length
                slens = BitConverter.GetBytes(slen)
    
                '发送长度
                For i = 0 To 7
                    tcpc.GetStream.WriteByte(slens(i))
                Next
                '发送内容
                tcpc.GetStream.Write(mem.ToArray, 0, mem.Length)
                tcpc.Close()
            End While
        End Sub
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Me.BackgroundWorker1.RunWorkerAsync()
        End Sub
    End Class
    



  • 相关阅读:
    [无聊测试赛] T12 道路
    [无聊测试赛] T9 矩阵覆盖
    [无聊测试赛] T10 所驼门王的宝藏
    [无聊测试赛] T8 佳佳的魔法药水
    [无聊测试赛] T7 豪华游轮
    [无聊测试赛] T6 排行榜
    【模板】三分求函数极值
    树的重心模板
    倍增最近公共祖先(LCA)
    ccf201612题解
  • 原文地址:https://www.cnblogs.com/liguangsunls/p/7294641.html
Copyright © 2011-2022 走看看