unexpected characters in TCP-communication

P

Peter Pippinger

Hello NG,

i have 2 functions to read and write strings on a TCP-socket.
The strange thing is, that sometimes there are unexpected characters
in the string.

First of all, have i understood it right,
- that i say in the first byte of the string - i want to send - the
number of chars, that i will send?
- that the fist byte of a string - i recieve - declares the number of
chars, i´ll get?

One example of my problem:
I expect one string "UNBEKANNTER PROZESS".
Sometimes i get for example "#UNBEKANNTER PROZESS".
Which gets me into trouble when working with this string...

Does someone have an idea, what goes wrong with this?

*** There is no cleaning-personal in the server-room which could
stumble over cables ;-) ***

The functions i use:

///
***************************************************************************­
*****************************
/// <summary>
/// Gibt den Wert eines ASCII-Zeichens zurück
/// </summary>
/// <param name="src">ASCII-Zeichen</param>
/// <returns>ASCII-Wert</returns>
///
***************************************************************************­
*****************************
public static byte Asc(char src)
{
// ASCII Wert eines Zeichens zurückgeben
return (System.Text.ASCIIEncoding.ASCII.GetBytes(src +
"")
[0]);
}


///
***************************************************************************­
*****************************
/// <summary>
/// Gibt ein ASCII-Zeichen für einen Wert zurück
/// </summary>
/// <param name="src">ASCII-Wert</param>
/// <returns>ASCII-Zeichen</returns>
///
***************************************************************************­
*****************************
public static char Chr(byte src)
{
// Zeichen zu einem ASCII Wert zurückgeben
return (System.Text.ASCIIEncoding.ASCII.GetChars(new
byte[] { src })[0]);
}


///
***************************************************************************­
*****************************
/// <summary>
/// Sendet einen String über einen Socket
/// </summary>
/// <param name="socket">Socket</param>
/// <param name="stringData">String</param>
///
***************************************************************************­
*****************************
public void write_string_on_socket(Socket socket, String
stringData)
{
// Länge des Strings festlegen, die übertragen wird
stringData = Chr((byte)stringData.Length).ToString() +
stringData;


// Nachricht an Server senden
socket.Send(Encoding.ASCII.GetBytes(stringData));
}


///
***************************************************************************­
*****************************
/// <summary>
/// Liest einen Sting über einen Socket
/// </summary>
/// <param name="socket">Socket</param>
/// <returns>String</returns>
///
***************************************************************************­
*****************************
public string read_string_from_socket(Socket socket)
{
// Empfangspuffer
byte[] data = new byte[1024];


// ermitteln, wieviele Bytes uns der Server schicken
möchte
int recv = socket.Receive(data);
int byte_anzahl = (int)data[0];


// jetzt den eigentlichen String mit der vorher
ermittelten Länge holen
recv = socket.Receive(data);
string stringData = Encoding.ASCII.GetString(data, 0,
byte_anzahl);


// empfangene Nachricht zurückgeben
return stringData;
}
 
C

Chris Dunaway

Hello NG,


First of all, have i understood it right,
- that i say in the first byte of the string - i want to send - the
number of chars, that i will send?
- that the fist byte of a string - i recieve - declares the number of
chars, i´ll get?

No, I don't believe this is correct. When sending an array of bytes,
the entire array is sent so there is no need to specify the number of
bytes to send in the array.

When receiving, the return value from the Receive command indicates
the number of bytes received.
 
P

Peter Pippinger

No, I don't believe this is correct.  When sending an array of bytes,
the entire array is sent so there is no need to specify the number of
bytes to send in the array.

When receiving, the return value from the Receive command indicates
the number of bytes received.

But if i connect my service for example with telnet the first "HELLO"
of the handshake only appears in telnet, if i my fist byte of the
sended string has the Value 5 (5 + "HELLO"). If the first Byte of the
Sting is 4 then only "HELL" will apear in telnet...

So i think its right, first to send how many characters there will be
send.
 
I

Ignacio Machin ( .NET/ C# MVP )

Hello NG,

i have 2 functions to read and write strings on a TCP-socket.
The strange thing is, that sometimes there are unexpected characters
in the string.

Most probably cause of the encoding.
First of all, have i understood it right,
- that i say in the first byte of the string - i want to send - the
number of chars, that i will send?

Yes, that is ok, I would use Int32 instead of byte but that's ok
- that the fist byte of a string - i recieve - declares the number of
chars, i´ll get?

Humm, I think that both cases are the same no?
If you are sending a variable amount of data you should send
previously the number of bytes you are going to send next.
 
B

Barry Kelly

Peter Pippinger wrote:

Hi Peter, I think there are a number of misconceptions about socket
programming in your code. Also, I think your conversions to and from
Pascal strings are faulty.
public static byte Asc(char src)
public static char Chr(byte src)

These functions aren't doing what you think they're doing. They replace
all characters above ordinal 127 with '?', ordinal 63. Any time your
string has a length above 127, you'll get 63 as your length character.
// Länge des Strings festlegen, die übertragen wird
stringData = Chr((byte)stringData.Length).ToString() +
stringData;
// Nachricht an Server senden
socket.Send(Encoding.ASCII.GetBytes(stringData));

public string read_string_from_socket(Socket socket)
{
byte[] data = new byte[1024];
int recv = socket.Receive(data);

Note that you may have received more than 1 byte in this call to Receive
- indeed, you may have received 0 bytes, if the other end has
disconnected.
int byte_anzahl = (int)data[0];
recv = socket.Receive(data);

Here, you may be overwriting the old bytes you received, because you
aren't taking care with the number of bytes read (the value in recv from
the last call).

Reading data from a socket is tricky because the data can come in lumps
with arbitrary breaks in the middle. This means that you need to loop
until you see all the data you need. Also, the data may have overlapped
beyond the end of one transmission, when you have the Nagle algorithm
enabled (which is the default). That is, multiple sends can get
coalesced, so that you see only a single read on the other side.

To avoid some of these problems, consider using a BufferedStream wrapped
around a NetworkStream to read out your strings. Then you can use code
roughly like the following:

---8<---
static byte[] StringToPString(string s)
{
char[] chars = s.ToCharArray();
int length = chars.Length > 255 ? 255 : 0;
int resultLen;
// Loop to get our length under 256. This ought to be
// trivial, but surrogate pairs can complicate things.
// This code doesn't throw errors on string truncation,
// which may be a more desirable alternative.
for (;;)
{
resultLen = Encoding.ASCII.GetByteCount(
chars, 0, length);
if (resultLen > 255)
--length;
else
break;
}
// Now length chars, when decoded, will fit into
// a Pascal string.
byte[] result = new byte[resultLen + 1];
Encoding.ASCII.GetBytes(chars, 0, length, result, 1);
result[0] = (byte) resultLen;
return result;
}

static byte[] ReadPString(BufferedStream s)
{
byte[] buf = new byte[256];
int read = s.Read(buf, 0, 1);
if (read == 0)
throw new EndOfStreamException();
int toRead = buf[0];
int offset = 1;
while (toRead > 0)
{
read = s.Read(buf, offset, toRead);
if (read == 0)
throw new EndOfStreamException();
toRead -= read;
offset += read;
}
return buf;
}

static string PStringToString(byte[] data)
{
int len = data[0];
return Encoding.ASCII.GetString(data, 1, len);
}
--->8---

Hopefully this gives you the general gist of how to approach both Pascal
string conversion in .NET, and socket I/O.


-- Barry
 
C

Chris Dunaway

The Socket.Send() method only sends the bytes you ask it to. It sends no
other meta-data, such as the length of the transmission, and thus the
receiver obviously receives no such meta-data that it could use to
reconstruct the array.


It does indicate the number of bytes received. But that doesn't tell you
how many bytes were sent.

Pete

Thanks,

I was just going by the docs for Send and Receive. I didn't realize
that a Pascal string was being sent (as alluded by Barry in another
response) where the string is preceded by the length.

Cheers,

Chris
 
Top