使用Net.Sockets.TcpListener和Net.Sockets.TcpClient进行图片传输时如何精确控制接收缓存数组大小

原创 2014年07月30日 06:23:24

<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这么小,该如何精确控制缓冲区呢?


其实我们可以很容易的解决这个问题,就像很多文件格式所做的事情一样,我们可以在Stream的前几个字节写入实际有效数据的长度,然后根据这个长度来分配内存,再读取内容,我所做的客户端与服务器之间传递屏幕的源代码如下:


'----------------客户端----------------

<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





'------------服务器----------------

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



【VB.Net】最直白的TcpClient代码

从网上甚至MSDN上找的关于TcpClient的代码大多都是非常简单让你无法改造或者C#代码直接转换不成VB的,今天就非常直白的把我的代码写出来以便初学VB的人使用TcpClient。 现在开始一步...
  • runplus
  • runplus
  • 2015-10-10 10:52:01
  • 2847

TCP服务端vb.net支持多客户端连接

Imports System.Threading Imports System.IO Imports System.Net Imports System.Net.Sockets Public Cla...
  • pengwu666
  • pengwu666
  • 2014-10-25 16:36:04
  • 2235

【VB.Net】最直白的TcpListener监听代码

【要点】 正确导入命名空间使用线程处理业务对异常进行控制,异常是难免的,注意捕捉并正确处理逻辑 【导入命名空间】 Imports System.Net Imports System.Net.So...
  • runplus
  • runplus
  • 2015-10-10 09:51:13
  • 2117

C# Net.Sockets 使用TcpListener发送接收数据

using System; using System.Net; using System.Net.Sockets; namespace TY.Net {     ///     /// ...
  • ty_soft
  • ty_soft
  • 2012-02-14 18:48:56
  • 3229

TcpListener的对象“已过时”的处理

今天在初始化监听请求的对象TcpListener 后,编译时出现一个警告,说“TcpListener listener = new TcpListener(5000),已过时,建议使用listener...
  • yuyue618
  • yuyue618
  • 2008-04-12 01:13:00
  • 2611

C#与<em>VB.NET</em>网络通信开发实战

C#与<em>VB.NET</em>网络通信开发技术的教程,涵盖套接字编程、串行通信、指纹识别、红外...使用Net.Sockets.<em>TcpListener</em>和Net.Sockets.TcpClient... 上传资源 万水...
  • 2018年04月13日 00:00

有关socket通信包大小的问题总结(UDP传输模式)

最近刚接触linux的编程,在pc机上编了两个socket通信的程序做测试,一个采用TCP的方式,另一个采用UDP的方式。不断增大传输数据包的大小,到180k大小时,UDP通信收不到包,阻塞在recv...
  • L_serein
  • L_serein
  • 2011-07-06 23:09:35
  • 5578

socket缓存大小

这个大小无法固定,在编程的时候也不要指望它能够固定。  1460这个数值大概是MTU通信术语 最大传输单元(Maximum Transmission Unit,MTU)是指一种通信协议的某一层上面所能...
  • jjjfew
  • jjjfew
  • 2011-05-12 01:02:00
  • 4626

<em>TCP</em>客户端类C<em>TCP</em>Client

<em>TcpListener</em>类与TcpClient类的使用 <em>TcpListener</em>(服务...<em>vb</em>RichClient例程,包括多线程,sqlite,cRPCconnection ...而被锁定帐户,如有疑问,请联络:webmaster@csdn.<em>net</em>...
  • 2018年04月16日 00:00

C# <em>TCP</em> 同步 异步Socket类

C#网络编程系列文章(三)之<em>TcpListener</em>实现异步TCP服务器 C#的TCP异步SOCKET通讯...一个基于<em>VB.net</em>的异步Socket网络TCP通信 立即下载 上传者: winy_em 时间: 2017...
  • 2018年04月14日 00:00
收藏助手
不良信息举报
您举报文章:使用Net.Sockets.TcpListener和Net.Sockets.TcpClient进行图片传输时如何精确控制接收缓存数组大小
举报原因:
原因补充:

(最多只允许输入30个字)