Network Stream behaving strangely.

O

Ofer Achler

I have an annoying problem,

I'm connecting to a server at port 6543 (doesn't really matter) and
trying to exchange information.

The protocol works this way:
i send 8 bytes that contain the number of bytes following (i. e. to send
"hello" you send it this way:
5 hello
)

And the recieve response is in the same format, first 8 bytes is the #
of bytes in the message.

The problem i'm having is that when i send then recieve, the netstream
object skipps over the header and reads something in the middle of the
message.

The really strange part is if i put a break point at where its supposed
to read the bytes, it reads everything correctly. If i put a breakpoint
outside the method that reads, it fails. Makes it quite hard to debug.

Any suggestions?

Here's some sample code:
public string Recv ( )
{
if (Connected)
{
Byte[] RecvBufSize = new Byte[8];
string retData,buffer;
Encoding ASCII = Encoding.ASCII;

// Receive number of bytes for this message
Int32 bytes = socket.Read(RecvBufSize, 0, 8);

buffer = ASCII.GetString(RecvBufSize, 0, bytes);

// Theres a bug somewhere that makes us read too late
Byte[] RecvBytes = new Byte[Convert.ToInt32(buffer)];

// Recieve the full message
bytes = socket.Read(RecvBytes, 0, RecvBytes.Length);

retData = ASCII.GetString(RecvBytes, 0, bytes);

return retData;
}
return null;
}
 
C

C# Learner

Ofer said:
[...]

The problem i'm having is that when i send then recieve, the netstream
object skipps over the header and reads something in the middle of the
message.

[...]

Any suggestions?

[...]

A problem with your code is that it isn't able to handle the fact that a
Read() attempt might return less data than you're asking it for. This
/could/ cause your issue as stated above.

You could use System.Diagnostics.Trace.Assert() to check whether this is
causing your error.

i.e.:

//...
Int32 bytes = socket.Read(RecvBufSize, 0, 8);
System.Diagnostics.Trace.Assert(bytes == 8);
//...
bytes = socket.Read(RecvBytes, 0, RecvBytes.Length);
System.Diagnostics.Trace.Assert(bytes == RecvBytes.Length);
//...

However, you should create a method to read 'n' bytes from the stream,
and not stop until all 'n' have been read, or the socket was disconnected.

For example:

static byte[] ReadFully(NetworkStream stream, int length)
{
byte[] result = new byte[length];

int total = 0;
do {
int n = stream.Read(result, 0, length - total);
if (n == 0) {
throw new SocketException("Disconnected.");
}

total += n;
} while (total < length);

return result;
}

Then, instead of a line like this:
bytes = socket.Read(RecvBytes, 0, RecvBytes.Length);

....use a line like this:
RecvBytes = ReadFully(socket, RecvBytes.Length);

....and so on.

Note that your variable naming style makes it overly difficult to read
and understand your code. I noticed the following:

- 'RecvBufSize' sounds like the name of an integer variable holding a
size value.
- 'RecvBufSize' has a capital first letter, which is the standard
practise for naming *constants* in C#.
- 'bytes' sounds like the name of a byte array variable.
- 'socket' sounds like the name of a socket variable. I presume this is
the name of a stream variable? If so, perhaps it should be called
'stream'?

This is just a constructive criticism; a good naming convention will
help you write well-behaving code :)
 
O

Ofer Achler

C# Learner wrote:


It worked! thank you!! I was soo frustrated!!!
A problem with your code is that it isn't able to handle the fact that a
Read() attempt might return less data than you're asking it for. This
/could/ cause your issue as stated above.
It has, it has!! i thought the packet size issue would be resolved
because i can specify how much the stream can read, apperantly, thats
not true =)
You could use System.Diagnostics.Trace.Assert() to check whether this is
causing your error.

i.e.:

//...
Int32 bytes = socket.Read(RecvBufSize, 0, 8);
System.Diagnostics.Trace.Assert(bytes == 8);
//...
bytes = socket.Read(RecvBytes, 0, RecvBytes.Length);
System.Diagnostics.Trace.Assert(bytes == RecvBytes.Length);
//...

Yes, i did, and that totally showed me its not reading the amount its
supposed to, thank you for teaching me how to use the assert function.
I used to use it in C++, but didnt know how to use it with .NET =)
However, you should create a method to read 'n' bytes from the stream,
and not stop until all 'n' have been read, or the socket was disconnected.

For example:

static byte[] ReadFully(NetworkStream stream, int length)
{
byte[] result = new byte[length];

int total = 0;
do {
int n = stream.Read(result, 0, length - total);
if (n == 0) {
throw new SocketException("Disconnected.");
}

total += n;
} while (total < length);

return result;
}

I took this code and modified it a little (it doesn't quite work as it
is) and am planning to release it in a GPL program, i assume that's ok.

Note that your variable naming style makes it overly difficult to read
and understand your code. I noticed the following:

- 'RecvBufSize' sounds like the name of an integer variable holding a
size value.
yeah, it was messy because i had to have a byte[] array to recieve the
number before i could convert it to a number. Now i'm doing it inline
- 'RecvBufSize' has a capital first letter, which is the standard
practise for naming *constants* in C#.
Yeah, i figured that out recently but havent updated all of my code
(i'll do it when i do modifications here and there :)
- 'bytes' sounds like the name of a byte array variable.
- 'socket' sounds like the name of a socket variable. I presume this is
the name of a stream variable? If so, perhaps it should be called
'stream'?

I used to use the System.Network.Socket class till a friend showed me
the tcp client and netstream classses, i didn't change the variable
names because i have many methods that use the socket object.
This is just a constructive criticism; a good naming convention will
help you write well-behaving code :)
Thanks, youve been a good helpl :)
 
C

C# Learner

Ofer said:
C# Learner wrote:

It worked! thank you!! I was soo frustrated!!!

Great :)
It has, it has!! i thought the packet size issue would be resolved
because i can specify how much the stream can read, apperantly, thats
not true =)

I believe this can happen due to the nature of TCP/IP.

On http://floppsie.comp.glam.ac.uk/Glamorgan/gaius/security/5tcpip.html
it reads:

12. Fragmentation and reassembly

* IP datagrams may be fragmented en route
o if intermediate nodes cannot cope with a large datagram (MTU
(maximum transmission unit) is smaller than datagram size)
* IP datagrams may be reassembled en route
o although not a good idea as routing is dynamic. (So datagrams may
not always travel the same route)
[...]

I took this code and modified it a little (it doesn't quite work as it
is) and am planning to release it in a GPL program, i assume that's ok.

Sure, no problem.
[...]

Thanks, youve been a good helpl :)

No problem -- I'm glad it helped :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top