i'm creating socket based system communicating between desktop , mobile devices. i'm using simple protocol reading , writing data streams between devices end bytes:
- first 4 bytes represent integer, defines type of command executed
- next 4 bytes represent integer, length of rest of bytes in stream
- the remaining bytes represent payload data, total number of corresponds result of (2.)
i'm able strip off first 4 bytes , resolve command ok, strip off next 4 bytes , resolve length correctly. problem comes when strip off remaining bytes, of them missing, , they're missing front of remaining data.
for example; if command 1, , length 50, there should 50 bytes left in stream there's 46 , it's bytes 0-3 missing.
the starting data follows:
- command: 1
- length: 50
- payload: c:\users\dave\music\offaiah-trouble_(club_mix).mp3
after converting byte array, get:
"\u0001\0\0\02\0\0\0c:\users\dave\music\offaiah-trouble_(club_mix).mp3"
(question - why first integer \u000 in front of , second not?)
here's snippets of code i'm using parse this:
ibuffer inbuffer = new windows.storage.streams.buffer(4); await _socket.inputstream.readasync(inbuffer, 4, inputstreamoptions.none); int command = bitconverter.toint32(inbuffer.toarray(), 0);
the inbuffer @ point contains: "\u0001\0\0\0", , bitconverter resolves 1
inbuffer = new windows.storage.streams.buffer(4); await _socket.inputstream.readasync(inbuffer, 4, inputstreamoptions.none); int length = bitconverter.toint32(inbuffer.toarray(), 0);
the inbuffer contains: "2\0\0\0", , bitconverter resolves "50"
inbuffer = new windows.storage.streams.buffer((uint)length); await _socket.inputstream.readasync(inbuffer, (uint)length, inputstreamoptions.partial); string path = encoding.utf8.getstring(inbuffer.toarray());
the inbuffer contains: "sers\dave\music\offaiah-trouble_(club_mix).mp3"
where did missing "c:\u" go front of this?
so, realised kept getting down-voted because question wasn't concise , reproducible. created small project demonstrate part of problem, , ironically enough problem went away.
here's code:
public sealed partial class mainpage : page { private streamsocketlistener _listener; private streamsocket _client; private streamsocket _socket; private hostname _host; private int _port = 54321; public mainpage() { initializecomponent(); _listener = new streamsocketlistener(); _listener.connectionreceived += async (sender, args) => { _socket = args.socket; await receive(); }; _host = networkinformation.gethostnames().firstordefault(x => x.ipinformation != null && x.type == hostnametype.ipv4); } protected async override void onnavigatedto(navigationeventargs e) { base.onnavigatedto(e); await _listener.bindendpointasync(_host, $"{_port}"); await task.run(async () => { _client = new streamsocket(); await _client.connectasync(_host, $"{_port}"); int command = 1; byte[] cmd = bitconverter.getbytes(command); byte[] path = encoding.utf8.getbytes(@"c:\users\dave\music\offaiah-trouble_(club_mix).mp3"); byte[] length = bitconverter.getbytes(path.length); byte[] result = cmd.concat(length.concat(path)).toarray(); await _client.outputstream.writeasync(result.asbuffer()); }); } private async task receive() { while (true) { ibuffer inbuffer = new windows.storage.streams.buffer(4); await _socket.inputstream.readasync(inbuffer, 4, inputstreamoptions.none); int command = bitconverter.toint32(inbuffer.toarray(), 0); //the inbuffer @ point contains: "\u0001\0\0\0", , bitconverter resolves 1 inbuffer = new windows.storage.streams.buffer(4); await _socket.inputstream.readasync(inbuffer, 4, inputstreamoptions.none); int length = bitconverter.toint32(inbuffer.toarray(), 0); //the inbuffer contains: "2\0\0\0", , bitconverter resolves "50" inbuffer = new windows.storage.streams.buffer((uint)length); await _socket.inputstream.readasync(inbuffer, (uint)length, inputstreamoptions.partial); string path = encoding.utf8.getstring(inbuffer.toarray()); } } }
if create new blank universal project , run this, you'll see produces correct output.
eventually worked out had race conditions between stream reader , one. in main project, don't read bytes in 1 go. have separate method reading , parsing "command" before passing control off method redirect control 1 of several worker methods service particular command - stripping off length , rest of payload thereafter.
the problem 'command reader' reading 4 bytes stream, before worker read off it's payload.
obviously answer should pause here , wait worker finish, i'm using async , await throughout surprised me having problem. cause missing await, , dreaded async void, follows..
the offending code:
private async task listen() { while (true) { //expects 4 byte packet representing command debug.writeline($"listening socket command..."); ibuffer inbuffer = new windows.storage.streams.buffer(4); await _socket.inputstream.readasync(inbuffer, 4, inputstreamoptions.none); int command = bitconverter.toint32(inbuffer.toarray(), 0); debug.writeline($"command received: {command}"); parsecommand(command); } } private async void parsecommand(int command) { //... }
...and ammended version:
private async task listen() { while (true) { //expects 4 byte packet representing command debug.writeline($"listening socket command..."); ibuffer inbuffer = new windows.storage.streams.buffer(4); await _socket.inputstream.readasync(inbuffer, 4, inputstreamoptions.none); int command = bitconverter.toint32(inbuffer.toarray(), 0); debug.writeline($"command received: {command}"); await parsecommand(command); } } private async task parsecommand(int command) { //... }
Comments
Post a Comment