c# - TcpClient read OutOfMemoryException -
c# - TcpClient read OutOfMemoryException -
i have problem intermittent outofmemoryexception, on line
buffer = new byte[metadatasize];
(under //read command's meta data.)
does mean seek read finish message while part of has been received? in case, reliable way handle that? btw, need variable length messages, short, while occasional messages large. should attach finish message size in front end of message? still, how can know how much stream contains before trying read it? (as seems read fails when trying read specific length, do)
public static command read(networkstream ns) { seek { //read command's type. byte[] buffer = new byte[4]; int readbytes = ns.read(buffer, 0, 4); if (readbytes == 0) homecoming null; commandtype cmdtype = (commandtype)(bitconverter.toint32(buffer, 0)); //read cmdid buffer = new byte[4]; readbytes = ns.read(buffer, 0, 4); if (readbytes == 0) homecoming null; int cmdid = bitconverter.toint32(buffer, 0); //read metadatatype buffer = new byte[4]; readbytes = ns.read(buffer, 0, 4); if (readbytes == 0) homecoming null; var metatype = (metatypeenum)(bitconverter.toint32(buffer, 0)); //read command's metadata size. buffer = new byte[4]; readbytes = ns.read(buffer, 0, 4); if (readbytes == 0) homecoming null; int metadatasize = bitconverter.toint32(buffer, 0); //read command's meta data. object cmdmetadata = null; if (metadatasize > 0) { buffer = new byte[metadatasize]; int read = 0, offset = 0, toread = metadatasize; //while while (toread > 0 && (read = ns.read(buffer, offset, toread)) > 0) { toread -= read; offset += read; } if (toread > 0) throw new endofstreamexception(); // readbytes = ns.read(buffer, 0, metadatasize); //if (readbytes == 0) // homecoming null; // readbytes should metadatasize, should check? binaryformatter bf = new binaryformatter(); memorystream ms = new memorystream(buffer); ms.position = 0; cmdmetadata = bf.deserialize(ms); ms.close(); } //build , homecoming command command cmd = new command(cmdtype, cmdid, metatype, cmdmetadata); homecoming cmd; } grab (exception) { throw; } } write method:
public static void write(networkstream ns, command cmd) { seek { if (!ns.canwrite) return; //type [4] // type enum, of fixed 4 byte length. can write it. byte[] buffer = new byte[4]; buffer = bitconverter.getbytes((int)cmd.commandtype); ns.write(buffer, 0, 4); ns.flush(); // write cmdid, fixed length [4] buffer = new byte[4]; // using same buffer buffer = bitconverter.getbytes(cmd.cmdid); ns.write(buffer, 0, 4); ns.flush(); //metadatatype [4] buffer = new byte[4]; buffer = bitconverter.getbytes((int)cmd.metadatatype); ns.write(buffer, 0, 4); ns.flush(); //metadata (object) [4,len] if (cmd.metadata != null) { binaryformatter bf = new binaryformatter(); memorystream ms = new memorystream(); bf.serialize(ms, cmd.metadata); ms.seek(0, seekorigin.begin); byte[] metabuffer = ms.toarray(); ms.close(); buffer = new byte[4]; buffer = bitconverter.getbytes(metabuffer.length); ns.write(buffer, 0, 4); ns.flush(); ns.write(metabuffer, 0, metabuffer.length); ns.flush(); if (cmd.metadatatype != metatypeenum.s_tick) console.writeline(cmd.metadatatype.tostring() + " meta: " + metabuffer.length); } else { //write 0 length metadatasize buffer = new byte[4]; buffer = bitconverter.getbytes(0); ns.write(buffer, 0, 4); ns.flush(); } } grab (exception) { throw; } } vb.net:
private tcp new tcpclient private messenger inmessenger private ns networkstream public sub new(byval messenger inmessenger) me.messenger = messenger end sub public sub connect(byval ip string, byval port integer) seek tcp = new tcpclient debug.print("connecting " & ip & " " & port) 'connect 5sec timeout dim res = tcp.beginconnect(ip, port, nothing, nothing) dim success = res.asyncwaithandle.waitone(5000, true) if not success tcp.close() else if tcp.connected ns = new networkstream(tcp.client) dim bw new system.componentmodel.backgroundworker addhandler bw.dowork, addressof doread bw.runworkerasync() end if end if grab ex exception trac.exception("connection effort exception", ex.tostring) closeconnection() end seek end sub private sub doread() seek while me.tcp.connected ' read continuously : dim cmd = commandcoder.read(ns) if cmd isnot nil handlecommand(cmd) else trac.traceerror("socket.doread", "cmd nothing") closeconnection() exit while end if if tcp.client nil trac.traceerror("socket.doread", "tcp.client = nothing") exit while end if end while grab ex exception trac.exception("socket.doread exception", ex.tostring()) closeconnection() eventbus.raiseerrordisconnect() end seek end sub edit:
i set in writeline's, , found packages sent recognized wrong size on receiver side. metadatasize should 9544 message, read 5439488, or similar wrong value. assume on few occations number big causes outofmemoryexception.
seems douglas' reply may on mark(?), test. info: server (sender) programme built "any cpu", ran on windows 7 x64 pc. while client (receiver) built x86, , (during test) ran on xp. must coded work on other windows x86 or x64.
you're talking packets, that's not concept exposed tcp. tcp exposes stream of bytes, nil more. doesn't care how many send calls there were. can split 1 send phone call multiple reads, , merge multiple sends, or mix of these.
the homecoming value of read tells how many bytes read. if value larger 0, smaller length passed read, got less bytes passed it. code assumes either 0 or length bytes read. invalid assumption.
your code suffers endian issues, think both of systems little endian, it's unlikely causing current problems.
if don't care blocking(your existing code blocks in loop, no additional issue) can utilize binaryreader on stream.
it has helper methods readint32 automatically take care of partial reads, , uses fixed endianness(always little).
buffer = new byte[4]; readbytes = ns.read(buffer, 0, 4); if (readbytes == 0) homecoming null; int cmdid = bitconverter.toint32(buffer, 0); becomes:
int cmdid = reader.readint32(); it throw endofstreamexception if unexpectedly encounters end of stream, instead of returning null.
c# .net out-of-memory tcpclient
Comments
Post a Comment