使用Net.Sockets.TcpListener和Net.Sockets.TcpClient进行图片传输时如何精确控制接收缓存数组大小
程序员文章站
2023-01-29 16:52:10
在dotnet平台net.sockets.tcplistener和net.sockets.tcpclient已经为我们封装了所有socket关于tcp部分,操作也更为简单,面向数据流。使用tcpc...
在dotnet平台net.sockets.tcplistener和net.sockets.tcpclient已经为我们封装了所有socket关于tcp部分,操作也更为简单,面向数据流。使用tcpclient的getstream方法获取数据流后可以方便的对数据流进行读写操作,就如同本地磁盘的文件读写一样,使得程序员在设计程序时更为便捷简单。
但如果你使用过这两个对象进行数据传输的时候,你会发现问题也随之而来——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的前几个字节写入实际有效数据的长度,然后根据这个长度来分配内存,再读取内容,我所做的客户端与服务器之间传递屏幕的源代码如下:
"----------------客户端----------------
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
上一篇: Kali学习笔记24:Nikto、Skipfish
下一篇: 使用jsp下载excel文件