I have a server which communicates with Clients using a TCP Sockets .
I want to send an object from one of the client (Sender) to server which sends this object to another client (Receiver )
the object contains fields of different types like this
Class Test {
public string key;
public int id;
public string message;
public Test ()
{
// constructor code
}
}
my question is how to convert the object to array of bytes, and when receive this array of bytes in Receiver how to do the opposite operation (convert from array of bytes to objects)?
You need to serialize your object. There are plenty of ways of doing that in C#.
You can serialize your object to binary bytes, XML or custom forms. If you want binary bytes (apparently that's what you're looking for) you can use BinaryFormatter class.
From the MSDN example:
Test test = new Test();
FileStream fs = new FileStream("output", FileMode.Create);
// Construct a BinaryFormatter and use it to serialize the data to the stream.
BinaryFormatter formatter = new BinaryFormatter();
try
{
formatter.Serialize(fs, test);
}
catch (SerializationException e)
{
Console.WriteLine("Failed to serialize. Reason: " + e.Message);
throw;
}
finally
{
fs.Close();
}
Of course, instead of a FileStream object you will use a socket output stream to send data.
If you are considering multiple platforms, I would suggest you use an XML based serialization so you won't run into issues related to platform endianness (byte order).
Related
I have an array of class data which I'm serialising into a byte array then pushing it into a database. This program runs on a scheduled basis during the night. On the other end I have another program which pulls this data out of the database, processes it into a report - or at least that's the plan.
The class is incased in 2 namespaces, first the the application name, the second is just something to hold my structures. Eg below.
namespace FibreTrend
{
namespace Structures
{
[Serializable]
public class Trend
{
public Trend(DateTime date, string ref, int port)
{
Date = date;
Reference = ref;
PortNo = port;
}
public DateTime Date;
public string Reference;
public int PortNo;
}
}
}
{
// Function to take the trendData list, convert it to a byte array
// List<Structures.Trend> trendData;
BinaryFormatter bf = new BinaryFormatter();
using (MemoryStream mStream = new MemoryStream())
{
bf.Serialize(mStream, trendData.ToArray());
byte[] b = mStream.ToArray();
// code that pushes the array into the database...
}
}
I have a completely separate application which reads in the data from the database as the byte array. I then go to converting it from the bytes back to my data class.
using (MemoryStream mStream = new MemoryStream())
{
BinaryFormatter binaryFormat = new BinaryFormatter();
mStream.Write(data, 0, data.Length);
mStream.Seek(0, SeekOrigin.Begin);
Structures.Trend[] obj = (Structures.Trend[])binaryFormat.Deserialize(mStream);
}
And here is my error. Its telling me it wants the FibreTrend binary to deserialize the data. Why?? My Trend class is the same size, same data layout, its an exact copy and paste from my other project. Why is it insisting on needing my other binary file in companion. When I do put the binary with it then deserialise it into an object it comes put as a FibreTrend.Structures.Trend[]. I'm obviously not going to include the other binary file with it, I'm also not going to double handle the data converting it to a Report.Structures.Trend[]. Its just a stream of 1s and 0s, why can't I just push it into any class that I deem I want, isn't that the purpose of the cast to tell the compiler how I want the data ordered and structured?
Binary Serialized data stream contains a header with type information in it. You can refer to the Binary Format Data structure here. That's why you are getting that exception about missing assembly.
One way to solve your issue is by implementing a SerializationBinder that overrides the type to be deserialized into at runtime and set Binder property on BinaryFormatter. Here is a very good example.
A preferred solution would be to use alternative serialization formats such as XML, JSON.
I am implementing a client-server communication. I need to send a response to the client whose size may vary, because it contains a serialized array:
[Serializable]
public struct ServerResponse
{
public ApplicationAction ApplicationAction { get; set; }
public Product[] AssociatedProducts { get; set; }
}
What I am currently doing is serializing my instance of ServerResponse to XML using XmlSerializer (it wouldn't bother me at all to use another method my data doesn't need to be human-readable) and writing it on the socket stream like so:
XmlSerializer xmlSerializer = new XmlSerializer(typeof(ServerResponse));
NetworkStream networkStream = client.GetStream();
if (networkStream.CanWrite)
{
xmlSerializer.Serialize(networkStream, response);
}
My problem is that the client does not know the size of the data it needs to read.
My guess is to first send the size of the data and then all the data, but to do that I need to know
how can I get the actual size of a serialized object ?
Thanks
Befor you will send any data you should serialize your Stream to the memory using MemoryStream. Then you can take its lenght and multiply by sizeof(byte)
Your code will look something like this:
XmlSerializer xmlSerializer = new XmlSerializer(typeof(JsonQuestion));
NetworkStream networkStream = client.GetStream();
MemoryStream memoryStream = new MemoryStream();
xmlSerializer.Serialize(memoryStream, response);
var length = memoryStream.Length * sizeof(byte);
//Send size
...
//Send data
if (networkStream.CanWrite)
{
memoryStream.CopyTo(networkStream);
}
I've started windows mobile programming today and I have successfully connected to my server.
The application I am making on Visual Studio is not a universal application, but a Windows Mobile Application.
The API DataWriter is used to write data to an output stream, in the applications scenario the output stream is the socket. I.E:
DataWriter dw = new DataWriter(clientSocket.OutputStream);
One of the methods I have been looking at is WriteBytes and WriteBuffer
(Documentation can be found her for API documentation for DataWriter
.
Which method do I use, and why?
How can I convert this class and sent it to my server using the methods mentioned above.
public class Message
{
public string pas { get; internal set; }
public int type { get; internal set; }
public string us { get; internal set; }#
}
//the below code goes in a seperate function
DataWriter dw = new DataWriter(clientSocket.OutputStream);
Message ms = new Message();
ms.type = 1;
ms.us = usernameTextBox.Text;
ms.pas = usernameTextBox.Text;
//TODO: send ms to the server
Between the two methods, WriteBytes() seems like the simpler approach. WriteBuffer() offers you more control over the output buffer/stream, which you can certainly use if and when you need to. But, for all intents and purposes, if you just need to simply open a connection and send it a byte stream, WriteBytes() does the job.
How can I convert this class and sent it to my server
That's entirely up to you, really. What you have to do is define how you're going to "serialize" your class to transmit over the connection (and thereby have to "deserialize" it when the other code receives the data).
There are a few ways to do that, among many others. A straightforward approach (taken from the top answer on that linked question), would be to use the BinaryFormatter class. Something like this:
var ms = new Message();
ms.type = 1;
ms.us = usernameTextBox.Text;
ms.pas = usernameTextBox.Text;
byte[] serializedMessage;
var formatter = new BinaryFormatter();
using (var stream = new MemoryStream())
{
formatter.Serialize(stream, ms);
serializedMessage = ms.ToArray();
}
// now serializedMessage is a byte array to be sent
Then on the other end you'd need to deserialize it back to an object instance. Which might look something like this:
// assuming you have a variable called serializedMessage as the byte array received
Message ms;
using (var stream = new MemoryStream())
{
var formatter = new BinaryFormatter();
stream.Write(serializedMessage, 0, serializedMessage.Length);
stream.Seek(0, SeekOrigin.Begin);
ms = (Message)formatter.Deserialize(stream);
}
You can of course abstract these behind a simpler interface. Or if you're looking for any kind of human readability in the serialization you might try something like a JSON serializer and directly convert the string to a byte array, etc.
Edit: Note that this is really just an example of one of many ways to "serialize" an object. And, as pointed out by a user in comments below, there could be drawbacks to using this binary serializer.
You can use any serializer, really. You can even make your own. Technically overriding .ToString() to print all the properties and then calling that is a form of serialization. The concept is always the same... Convert the in-memory object to a transmittable piece of data, from which an identical in-memory object can later be built. (Technically, saving to a database is a form of serialization.)
I'm trying to encrypt a class before serializing it. The only way I found is to encrypt it and return a String or a stream, is it possible to return the original class ?
public static Options Encrypt(Options Settings)
{
Options sk = null;
try
{
using (var stream = new MemoryStream())
{
RuntimeTypeModel.Default.Serialize(stream, Settings);
byte[] data = encryptWithPadding(stream.ToArray(), 0);
String base64EncryptedString = Convert.ToBase64String(data);
// needs to return an option instance
}
}
catch (Exception e)
{
Global.LogError("Serialization failed", e);
}
return sk;
}
You can't "encrypt" a protobuf without serializing it. Encryption generally works on bytes, not data structures. If you want to encrypt it, and then embed the encrypted version as a field in some other protobuf, make that other field have type bytes instead of Options.
(In theory you could encrypt each of the fields of Options individually, but this would not help you much and would very likely be less secure than encrypting the whole serialized blob.)
How can I send variables/objects/data from one program to another in a LAN using TCP Socket? In particular, I want to send variables like TreeNode and ListViewItem. How can I do this? How will a sender program convert the variable to a form which it can send to another program in a LAN? And how will the receiver program bring back the sent variable to it's original form?
EDIT: Found the following code on a website which is no longer available and requested to remove the link.
// Convert an object to a byte array
private byte[] ObjectToByteArray(Object obj)
{
if (obj == null)
return null;
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, obj);
return ms.ToArray();
}
// Convert a byte array to an Object
private Object ByteArrayToObject(byte[] arrBytes)
{
MemoryStream memStream = new MemoryStream();
BinaryFormatter binForm = new BinaryFormatter();
memStream.Write(arrBytes, 0, arrBytes.Length);
memStream.Seek(0, SeekOrigin.Begin);
Object obj = (Object)binForm.Deserialize(memStream);
return obj;
}
You can serialize the data into a byte array and then send that? The receiver program would then de-serialize the data at the other end.
It is called serialization, and there are many types of it. Some types favor certain types of data, some types offer greater speeds than compression ratios, and some types offer greater compression ratios than speeds.
JSON.NET, Google Protocol Buffers, YaxLib...there are plenty, take your pick. Some are easier to use than others. I recommend JSON.NET because there are probably more tutorials online for that one, and it's humanly-readable while you're debugging.