4

I have established a TCP connection between two computers for sending and receiving data back and forth, in a windows application. The message that I am sending is a set of integers converted to string and split by ",". So, for sending the data I'd use,

if (dataSend.Length > 0)
{
    m_writer.WriteLine(dataSend);
    m_writer.Flush();
}

where dataSend is my message in the form of string, and m_writer is a StreamWriter.

But, now I want to send it as an array of integers over the same network connection but I can't find anything for it. I see a lot of people using byte array but with that I don't understand how, at the time of reading, the receiver would know how to split the bytes into the respective integer.

I realize that the writeline method allows for Int as its parameter too, but how do I send an array?
With string it was clear because I could separate the data based on "," and so I knew where each element would end. What would the separation criteria be for integer array?

It would be nice if someone would explain this to me, as I am also fairly new to the networks aspect of C#.

Follow up question: StreamReader does not stop reading C#

Community
  • 1
  • 1
Sanketh. K. Jain
  • 489
  • 1
  • 9
  • 24

5 Answers5

4

You're asking a question that will almost always end up being answered by using serialization and/or data framing in some form. Ie. "How do I send some structure over the wire?"

You may want to serialize your int[] to a string using a serializer such as XmlSerializer or the JSON.NET library. You can then deserialize on the other end.

int[] numbers = new [] { 0, 1, 2, 3};
XmlSerializer serializer = new XmlSerializer(typeof(int[]));
var myString = serializer.Serialize(numbers);

// Send your string over the wire
m_writer.WriteLine(myString);
m_writer.Flush();

// On the other end, deserialize the data
using(var memoryStream = new MemoryStream(data))
{
    XmlSerializer serializer = new XmlSerializer(typeof(int[]));
    var numbers = (int[])serializer.Deserialize(memoryStream);
}
Alex Wiese
  • 8,142
  • 6
  • 42
  • 71
  • 1
    this is a good, open-ended, way to do this, but is wasteful of transmission bandwidth. However - given that bandwidth is not at issue, if that is the case for you - you should definitely consider some sort of standardized serialization as the solution, for readability on the wire while troubleshooting. – John Castleman Feb 16 '15 at 05:17
  • 2
    Yes, using an existing serializer has the advantage of not having to write and test your own serializer (which is what he will effectively have to do to send anything less primitive over the wire), and can also be used to transfer other, more complex structures. – Alex Wiese Feb 16 '15 at 05:20
  • @JohnCastleman Bandwidth isn't currently an issue. But for future reference what other method would you recommend that would reduce the bandwidth? – Sanketh. K. Jain Feb 16 '15 at 05:24
  • @alexw Okay, so to be clear, I use XmlSerializer to serialize the integer array, then convert the serialized data to a byte array and then send the byte array over the connection? And on the receiving, I can simply read the byte array using memory stream and the deserialization will convert it to integer array? – Sanketh. K. Jain Feb 16 '15 at 05:27
  • Basically you have to send data over the socket as byte[], which could be the byte array representation of a string (such as in your case). As long as you have a way of encoding the data on one end and decoding it on the other, in a way that is reliable then your problem is solved. – Alex Wiese Feb 16 '15 at 05:27
  • @Sanketh.K.Jain Serialization will give you a string representation of an object, which can be sent over the connection. The other end you can turn it back into the object using deserialization. – Alex Wiese Feb 16 '15 at 05:28
  • 1
    This is a better method than you might think, because the serialization that is agreed upon and used on both sides represents a common "dictionary" that both sides of the transmission agree to, instead of having to invent your own language (as my answer would have you do ... a technique that used to be "de facto" for socket communications, before bandwidth became cheap as sin). – John Castleman Feb 16 '15 at 05:34
  • @Sanketh.K.Jain If bandwidth is an issue, this is still a solved problem .. see Protocol Buffers (my recommendation), Thrift (similar), and even ASN.1 (if you must, used in CORBA eg.) for existing well-defined binary encoding schemes. – user2864740 Feb 16 '15 at 22:45
  • @alexw What is the data that you are reading in the memory stream at the receiving end? – Sanketh. K. Jain Feb 18 '15 at 17:27
2

Okay a simply suggestion you can use

  • Sender first send the length of integer array.

  • Receiver create an array to receive this data

  • Sender in a loop use WriteLine() to send each element of the array (As string or int)

  • Receiver in a loop use ReadLine() to catch each element. and convert received string to integer

Sender :

m_writer.WriteLine(myarray.Length); // Sender sends the array length prior to data transmission

// Send all data
foreach(int item in myarray){
      m_writer.WriteLine(item.ToString());
}

Receiver :

int Size =Convert.ToInt32( m_reader.ReadLine()); //receiver receives the Length of incoming array 

int i=0;
// Receive all data
while(i < Size){
     Console.WrilteLine(Convert.ToInt32(m_reader.ReadLine())); // Add this to array
     i++;
}
Kavindu Dodanduwa
  • 12,193
  • 3
  • 33
  • 46
2

I'm going to give you an answer that assumes you want to actually transmit bytes, to keep the protocol light: if not accept alexw answer instead, because it's a pretty good one.

You should look at some form of message framing, or at the very least length prefixing. I've been dealing with TCP socket protocols for over a decade, and always used some form of this (mostly message framing). Lately, however, I've been using WCF instead, and that uses (.NET) serialization, so I'd actually tend toward alexw answer, given unlimited bandwidth (and a .NET stack a common architecture, or at least an agreed upon serialization algorithm, on both sides).

EDIT

Here's how that might look using simple length prefixing:

var myArray = new byte[10];
using (var stream = new MemoryStream())
using (var writer = new BinaryWriter(stream))
{
    writer.Write(myArray.Length);
    foreach (var b in myArray)
        writer.Write(b);
}

Of course, using this technique, both parties have to be in on it: you're establishing an Application-Level Protocol on top of TCP, and both sides have to be talking the same language (e.g., knowing that length is stored in a byte, knowing that we're only sending simple arrays of bytes, without further context ... see message framing for what "further context" might look like).

rene
  • 41,474
  • 78
  • 114
  • 152
John Castleman
  • 1,552
  • 11
  • 12
  • I really do like your answer, and I'll use it for any future reference, so thank you for that and your expertise on the other answers also. I've got to learn about message framing to understand what exactly I'll be getting into, so thank you. Until then, I get the XML serialization because I have dealt with XML formats earlier – Sanketh. K. Jain Feb 16 '15 at 14:00
  • No problem: I'm pushing for alexw answer to be the accepted answer all along, 'cause it's the best from a maintainability/portability POV. But thanks for the upvote! (assuming that was you) – John Castleman Feb 16 '15 at 19:12
1

You could serialize the data as XML but the down side is you end up creating a bloated string for such a simple set of numbers. Instead you should take advantage of the ability to send raw bytes.

To send an array of integers you would loop over your array of integers and write each one in turn to the stream. Use the Write method that takes an integer. But you also need to indicate to the other side how many integers are going to be sent. So begin by sending a number that is the count of integers to follow...

int[] values = new int[] { 1, 2, 3 };
m_writer.Write(values.Length);
foreach(int value in values)
    m_write.Write(value);

On the receiving side you read and integer and then that is the number of times you then need to read integers to recreate the array.

int count = m_reader.ReadInt32();
int[] values = new byte[count];
for(int i=0; i<values; i++)
    values[i] = m_reader.ReadInt32();

Obviously I have skipped any error checking, but I leave that as an exersize for the reader!

Phil Wright
  • 22,580
  • 14
  • 83
  • 137
0

Use Encoding.GetBytes(string) to get byte array for your string and Encoding.GetString(byte[]) to convert back to string.

byte[] arrBytes = Encoding.Default.GetBytes(dataSend);

Converting back to String

string dataRecieved = Encoding.Default.GetString(arrBytes);

Please note here, you can use a fixed encoding format, as the Default encoding on transmitter and receiver machine can be different.

Rohit Prakash
  • 1,975
  • 1
  • 14
  • 24