Casting string to type it resembles - c#

I'm trying to determine the best way to transfer a c# type across the network so when it gets to the other side, I can serialize it.
Right now, I am doing this
public void Send<T>(T packet) {
NetworkStream Stream = Server.GetStream();
byte[] typeName = Encoding.UTF8.GetBytes(typeof(T).FullName);
byte[] typeLength = BitConverter.GetBytes(typeName.Length);
byte[] packetdata = Encoding.UTF8.GetBytes(JsonSerializer.Serialize<T>(packet));
byte[] length = BitConverter.GetBytes(packetdata.Length);
Stream.Write(typeLength, 0, 4);
Stream.Write(typeName, 0, typeName.Length);
Stream.Write(length, 0, 4);
Stream.Write(packetdata, 0, packetdata.Length);
}
On the other end I want to do something like this
byte[] BufferedData = new byte[0];
while (Alive) {
byte[] StreamData = new byte[1024];
int bytesRead = Client.tcpClient.GetStream().Read(StreamData, 0, StreamData.Length); // Read data off the network
BufferedData = BufferedData.Join(StreamData.Sub(0, bytesRead)); // Pull the recieved data out and buffer it
// [TypeLength, TypeName, DataLength, Data]
if (BufferedData.Length > 4) { // If the packet length data has been received
int typeLength = BitConverter.ToInt32(BufferedData); // Gets the first 4 bytes off the data and puts it into the data length int
if (BufferedData.Length >= typeLength + 8) { // If the type and the data length of the packet has been received
int dataLength = BitConverter.ToInt32(BufferedData.Sub(typeLength + 4, 4)); // Get the data length off the packet
if (BufferedData.Length >= typeLength + dataLength + 8) { // If the whole packet has been received
string data = Encoding.UTF8.GetString(BufferedData.Sub(typeLength + 8, dataLength)); // Get the data as a string
Type x = Type.GetType(Encoding.UTF8.GetString(BufferedData.Sub(4, typeLength))); // Get the type of the data
-> x obj = (x)JsonSerializer.Deserialize<x>(data); // This is what i need to figure out
onReceived.Invoke(JsonSerializer.Deserialize<IMistoxPacket>(Encoding.UTF8.GetString(BufferedData.Sub(4, dataLength))), new EventArgs()); // Split out packet and send it up
BufferedData = BufferedData.Sub(dataLength, BufferedData.Length - dataLength); // Remove the packet from the Buffered data
}
}
}
}
How do i get x to be the type of x instead. so the obj can be the type of x. if that makes since
I don't know if this is a viable path or if there is a better way of doing something like this. I want to send multiple packet types across the same code and split them out later. Any help would be awesome.

Related

AsyncTCP C# - arduino/unity communication

I've been working the last weeks with a tcp protocol to send packet from arduino to unity using this code:
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;
public class TCPConnection : MonoBehaviour
{
public string IP_Seat = "192.168.137.161";
public int port = 34197;
#region private members
private TcpClient socketConnection;
private Thread clientReceiveThread;
public float a, b, c, vel;
public float test = 0.0f;
#endregion
// Use this for initialization
void Awake()
{
ConnectToTcpServer();
}
/// <summary>
/// Setup socket connection.
/// </summary>
private void ConnectToTcpServer()
{
try
{
clientReceiveThread = new Thread(new ThreadStart(ListenForData));
clientReceiveThread.IsBackground = true;
clientReceiveThread.Start();
}
catch (Exception e)
{
Debug.Log("On client connect exception " + e);
}
}
/// <summary>
/// Runs in background clientReceiveThread; Listens for incoming data.
/// </summary>
private void ListenForData()
{
var aold = 0.0f;
var bold = 0.0f;
var cold = 0.0f;
var velold = 0.0f;
try
{
socketConnection = new TcpClient(IP_Seat, port);
//cketConnection.ConnectAsync(IP_Seat, port); // non si connette
//socketConnection.Client.Blocking = false;
//socketConnection.Client.ConnectAsync(IP_Seat,port);
Byte[] bytes = new Byte[16];
while (socketConnection.Connected)
{
// Get a stream object for reading
using (NetworkStream stream = socketConnection.GetStream())
{
int length;
// Read incoming stream into byte arrary.
while ((length = stream.Read(bytes, 0, bytes.Length)) != 0)
{
//Debug.Log("I'm receiving Data");
if (length == 16)
{
//Debug.Log("I'm receiving len 16 and I like it");
var incomingData = new byte[length];
var A = new Byte[4];
var B = new Byte[4];
var C = new Byte[4];
var VEL = new Byte[4];
Array.Copy(bytes, 0, incomingData, 0, length);
// Convert byte array to string message.
string serverMessage = Encoding.ASCII.GetString(incomingData);
Array.Copy(bytes, 0, A, 0, 4);
Array.Copy(bytes, 4, B, 0, 4);
Array.Copy(bytes, 8, C, 0, 4);
Array.Copy(bytes, 12, VEL, 0, 4);
a = BitConverter.ToSingle(A, 0) < 0 ? BitConverter.ToSingle(A, 0) : aold;
b = BitConverter.ToSingle(B, 0) < 0 ? BitConverter.ToSingle(B, 0) : bold;
c = BitConverter.ToSingle(C, 0) < 0 ? BitConverter.ToSingle(C, 0) : cold;
vel = BitConverter.ToSingle(VEL, 0); //< 0 ? BitConverter.ToSingle(C, 0) : 0;
//Debug.Log("server message received as: " + serverMessage +a +" "+b + " " + c + " " + vel);
aold = a;
bold = b;
cold = c;
velold = vel;
}
else {
//evitare che bilancia aspetti ack di tcp
}
}
}
}
}
catch (SocketException socketException)
{
Debug.Log("Socket exception: " + socketException);
}
}
}
and right now i'm having blocking issues: i'd like to use the async method for the TCP but the tcpClient.ConnectAsync but it returns a SocketEXception and I can't figure out why.
The arduino sends 4 float in 16 bytes packet and 98-99% of them arrive correctly, but the missing 1-2% causes the system to block and an undesirable behaviour ( since i'm programming a device I need no delay waiting for an ack or a packet)
How can I make this sokcet async?
EDIT:
Using NET 4.X: how can I use the connectASync(ip,port) method in this script?
As already said TCP is just an undefined stream of data you need to implement an according protocol for knowing when a message ends (is fully received) and when a new one starts.
Now in your case you seem to already know that you have exactly 16 bytes.
NetworkStream.Read however, does not necessarily wait until actually 16 bytes where received. If for some reason (delay in the network) at the moment it is called there are less bytes in the stream then it will receive only the amount that is available.
Now let's say your sender sends 3 packages รก 16 bytes (so 48 bytes).
It might happen that the first time you read only 8 bytes. From now on every following read call receives 16 bytes.
=> Result: You get two complete buffers, but with invalid data since you always started reading at the middle of a message.
Note the second parameter of Read
int offset -> The location in buffer to begin storing the data to.
what you want to do is wait until the buffer is actually full like
var receivedBytes = 0;
while (receivedBytes < bytes.Length)
{
receivedBytes += stream.Read(bytes, receivedBytes, bytes.Length - receivedBytes);
}
// Use bytes
Now this will fill exactly one buffer of 16 bytes before continuing since at the same time we increase the offset we also decrease the maximum amount of bytes to read.
And another note: you have a huge amount of redundant array creations, copies and BitConverter going on!
I would rather use
var bytes = new byte[16];
var floats = new float[4];
And then later on after receiving the bytes do
Buffer.BlockCopy(bytes, 0, floats, 0, 16);
This copies the bytes over into floats directly in the underlaying byte layer.
And then you can simply do
a = floats[0] < 0 ? floats[0] : aold;
b = floats[1] < 0 ? floats[1] : bold;
c = floats[2] < 0 ? floats[2] : cold;
v = floats[3];
Note: Typed on the phone but I hope the idea gets clear

How do I read x amount from a buffer

For the sake of this question, let's assume nothing is wrong with the server and let's just focus on the client and how it receives the data.
So I have this client / server setup going and this is how it currently flows.
The server sends a packet that's 5000 bytes.
All the packets are structured like this.. The first 4 bytes are reserved for the length of the entire packet, the next byte is reserved for the OpCode.. The remaining bytes represents the actual payload.
Length (4 bytes) | OpCode (1 byte) | Payload (x bytes)
On the client I'm currently doing this
byte[] RawBuffer = new byte[Constants.BufferSize]; //Constants.BufferSize = 1024
int packLen = 0;
int totalReceived = 0;
private byte[] allData;
private void ReceiveCallback(IAsyncResult ar)
{
var stream = (NetworkStream)ar.AsyncState;
var received = stream.EndRead(ar);
Debug.Print($"Data received: {received} bytes");
//If we haven't assigned a length yet
if (packLen <= 0)
{
//Use "allData" as the final buffer that we use to process later down the line.
using (var ms = new MemoryStream(RawBuffer))
using (var reader = new BinaryReader(ms))
{
packLen = reader.ReadInt32();
allData = new byte[packLen];
}
}
Buffer.BlockCopy(RawBuffer, 0, allData, 0, received);
totalReceived += received;
if (totalReceived == allData.Length)
{
Debug.Print($"We've successfully appended {allData.Length} bytes out of {packLen}");
}
stream.BeginRead(RawBuffer, 0, Constants.BufferSize, ReceiveCallback, _stream);
}
That only works if I send 1 packet from the server to the client, but if I send 5 packets for instance it never actually splits them up.
How do I properly split them up so that once it's received the full packet based on the Length header, it prints out "Received packet successfully"

Modbus TCP Communication C#

I am looking for a little help.
I have a program to communicate with a controller through Modbus TCP.
The only problem is I cannot extend the Nop from 125 to 400 because I got Illegal Data Address error message.
Could you please help me with this?
try
{
byte slaveid = 1;
byte function = 4;
ushort id = function;
ushort startAddress = 0;
uint NoP = 125;
byte[] frame = ReadInputRegistersMsg(id, slaveid, startAddress, function, NoP);
this.Write(frame); //data send to controller
Thread.Sleep(100);
byte[] buffReceiver = this.Read(); //data recieving from controller
int SizeByte = buffReceiver[8]; // Data what I got from the controller
UInt16[] temp = null;
if (function != buffReceiver[7])
{
byte[] byteMsg = new byte[9];
Array.Copy(buffReceiver, 0, byteMsg, 0, byteMsg.Length);
byte[] data = new byte[SizeByte];
textBox2.Text = Display(byteMsg);
byte[] errorbytes = new byte[3];
Array.Copy(buffReceiver, 6, errorbytes, 0, errorbytes.Length);
this.CheckValidate(errorbytes); // check the answer -> error message
}
else
{
byte[] byteMsg = new byte[9 + SizeByte];
Array.Copy(buffReceiver, 0, byteMsg, 0, byteMsg.Length);
byte[] data = new byte[SizeByte];
textBox2.Text = Display(byteMsg); // Show received messages in windows form app
Array.Copy(buffReceiver, 9, data, 0, data.Length);
temp = Word.ConvertByteArrayToWordArray(data); // Convert Byte[]-> Word[]
}
// Result
if (temp == null) return;
string result = string.Empty;
//foreach (var item in temp) // show all the data
for(int i=0;i<100;i++) // show the first 100 data
{
//result += string.Format("{0} ", item);
result += temp[i];
}
textBox3.Text = result; // insert the result into the textbox (windows form app)
}
catch
{
}
The ReadInputRegister Message is the following:
private byte[] ReadInputRegistersMsg(ushort id, byte slaveAddress, ushort startAddress, byte function, uint NoP)
{
byte[] frame = new byte[12];
frame[0] = (byte)(id >> 8); // Transaction Identifier High
frame[1] = (byte)id; // Transaction Identifier Low
frame[2] = 0; // Protocol Identifier High
frame[3] = 0; // Protocol Identifier Low
frame[4] = 0; // Message Length High
frame[5] = 6; // Message Length Low(6 bytes to follow)
frame[6] = slaveAddress; // Slave address(Unit Identifier)
frame[7] = function; // Function
frame[8] = (byte)(startAddress >> 8); // Starting Address High
frame[9] = (byte)startAddress; // Starting Address Low
frame[10] = (byte)(NoP >> 8); // Quantity of Registers High
frame[11] = (byte)NoP; // Quantity of Registers Low
return frame;
}
The hard limit for modbus is 125 NoP

Reliable way to determine variable message length when receiving from socket

I have some Python code for capturing images from a camera and sending them to a C# server.
When sending the messages from the client- I precede the data with the message size so I know how much data to pull from the socket server-side.
It seems to work well most of the time, but occasionally - the message doesn't appear to start with the message size.
I'm not sure why this is happening but I can't figure out how to deal with it.
Python code:
while True:
send_message("SEND_FRAME_DATA_HERE")
def send_message(message):
message_size = len(message.encode())
print (f"Message: {message_size} - {message}")
my_socket.sendall(struct.pack(">L", message_size) + message.encode())
C#
private const int MESSAGE_CHUNK_SIZE = 4096;
private const int MESSAGE_PREFIX_SIZE = 4;
private void _receiveMessage(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
List<byte> messageBuffer = new List<byte>();
byte[] tempBuffer = new byte[MESSAGE_CHUNK_SIZE];
try
{
handler.EndReceive(ar);
messageBuffer.AddRange(state.messageBuffer);
while (true)
{
while (messageBuffer.Count < MESSAGE_PREFIX_SIZE)
{
handler.Receive(tempBuffer, 0, MESSAGE_CHUNK_SIZE, 0);
messageBuffer.AddRange(tempBuffer);
}
int messageLength = _getMessageLength(messageBuffer);
// Occasionally the four bytes determining message length
// are read from what appears to be mid message
if (messageLength > 20)
{
Console.Write("halp");
}
messageBuffer = messageBuffer.Skip(MESSAGE_PREFIX_SIZE).ToList();
while (messageBuffer.Count < messageLength)
{
handler.Receive(tempBuffer, 0, StateObject.messageChunkSize, 0);
messageBuffer.AddRange(tempBuffer);
}
var wholeMessage = messageBuffer.Take(messageLength).ToList();
var messageString = Encoding.Default.GetString(wholeMessage.ToArray());
Console.WriteLine(messageString);
messageBuffer = messageBuffer.Skip(messageLength).ToList();
}
}
catch (SocketException ex)
{
Console.WriteLine(ex.Message);
}
}
private int _getMessageLength(List<byte> message)
{
byte[] bytes = { message[3], message[2], message[1], message[0] };
return BitConverter.ToInt32(bytes, 0);
}
The message buffer should look something like this:
On a good run:
On a bad run:
The problem appears to be with this code:
handler.Receive(tempBuffer, 0, StateObject.messageChunkSize, 0);
messageBuffer.AddRange(tempBuffer);
Socket.Receive() returns the number of bytes actually read into the tempBuffer. You need to save that value, and then use it to copy the correct number of bytes to messageBuffer.
int bytesRead = handler.Receive(tempBuffer, 0, StateObject.messageChunkSize, 0);
messageBuffer.AddRange(tempBuffer.Take(bytesRead));

Network stream stuck on stream.Read(byte[] byte, int offset, int size)

What I'm trying to do is to received a large number of bytes (about 5MB data) sent from the client side
Below is the code where data(byte[]) is received
byte[] receivedBytesRaw = new byte[4000];
//first, initialize network stream
NetworkStream stream = client.GetStream();
//The bytesNeeded is the size of bytes which is a protocol sent by the client side indicating the size of byte which will be sent
int bytesNeeded = 4000;
int bytesReceived = 0;
do
{
int bytesRead = stream.Read(receivedBytesRaw, bytesReceived, bytesNeeded - bytesReceived);
networkValidation.addBytesToList(receivedBytesRaw, ref receivedBytes);
bytesReceived += bytesRead;
} while (bytesReceived < bytesNeeded);
But now I'm stuck on a problem:
Everytime when data arrives, the do while loop loops for the first time, and the return value (i) is 26, then it loops again, this time, when it goes to " i = stream.Read(receivedBytesRaw, 0, receivedBytesRaw.Length);", the program seems waiting for the client side to send data and have no response, also, when I check "receivedBytesRaw", the data was incomplete, only the first 13 bytes was received, the remaining space in the byte array remains null, and the stream.DataAvailable is false
Why the server side received incomplete data?
Note: when I try to send small data (a string), it's ok
=====================================================================
Edited
Below is the client side code which sends data:
private int sendData(byte[] dataSend, string IP, int portNumber)
{
TcpClient clientSide = new TcpClient();
int result = -1;
try
{
clientSide.Connect(IP, portNumber);
}
catch (Exception ex)
{
return 2;
}
NetworkStream netStream = clientSide.GetStream();
if (netStream.CanWrite)
{
byte[] replyMsg = new byte[1024];
netStream.Write(dataSend, 0, dataSend.Length);
netStream.Flush();
result = 0;
}
else
{
result = 1;
}
return result;
}
Because it's a stream, and can be partial received. Are you sure you are always receiving packages with te size of 2048 bytes?
int i = 0;
int bytesNeeded = 200;
int bytesReceived = 0;
do
{
//read byte from client
int bytesRead = stream.Read(receivedBytesRaw, bytesReceived, bytesNeeded-bytesReceived);
bytesReceived += bytesRead;
// merge byte array to another byte array
} while (bytesReceived < bytesNeeded);
I think you need a frame protocol, try create a protocol like, writing the size of the data that follows.
example: (psuedo)
void SendData(byte[] data)
{
// get the 4 bytes of a int value.
byte[] dataLength = BitConverter.GetBytes(data.Lenght);
// write the length to the stream.
stream.Write(dataLength, 0, dataLength.Length);
// write the data bytes.
stream.Write(data, 0, data.Length);
}
void Receive()
{
// read 4 bytes from the stream.
ReadBuffer(buffer, 4);
// convert those 4 bytes to an int.
int dataLength = BitConverter.ToInt32(buffer, 0);
// read bytes with dataLength as count.
ReadBuffer(buffer, dataLength);
}
// read until the right amount of bytes are read.
void ReadBuffer(byte[] buffer, int length)
{
int i = 0;
int bytesNeeded = length;
int bytesReceived = 0;
do
{
//read byte from client
int bytesRead = stream.Read(buffer, bytesReceived, bytesNeeded-bytesReceived);
bytesReceived += bytesRead;
// merge byte array to another byte array
} while (bytesReceived < bytesNeeded); // <- you should do this async.
}
This is just an example..
Another solution you could try is using async reads.
I made a class that reads until all bytes are read. If it isn't a problem that the complete file is read, you could try this:
Example:
This example show that you can read a simple protocol. ReadPacket handles a length + data message. So the sender will first send an int value containing the length of data that follows.
The StartReading method reads a filename and the filedata. It will store up to 10mb max filesize. But this isn't originally designed for receiving files.
const int MaxFileSize = 10 * 1024 * 1024;
private void Example()
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect("localhost", 12345);
StartReading(socket);
}
private void StartReading(Socket socket)
{
ReadPacket(socket, (filenameData) =>
{
if (filenameData.Count == 0)
{
// disconnected
return;
}
// parse the filename
string filename = Encoding.UTF8.GetString(filenameData.Array, filenameData.Offset, filenameData.Count);
Trace.WriteLine("Receiving file :" + filename);
ReadPacket(socket, (fileData) =>
{
if (fileData.Count == 0)
{
// disconnected
return;
}
Trace.WriteLine("Writing file :" + filename);
// write to the file
using (FileStream stream = new FileStream(filename, FileMode.Create, FileAccess.Write))
stream.Write(fileData.Array, fileData.Offset, fileData.Count);
// start waiting for another packet.
StartReading(socket);
});
});
}
private void ReadPacket(Socket socket, Action<ArraySegment<byte>> endRead)
{
// read header. (length of data) (4 bytes)
EasySocketReader.ReadFromSocket(socket, 4, (headerBufferSegment) =>
{
// if the ReadFromSocket returns 0, the socket is closed.
if (headerBufferSegment.Count == 0)
{
// disconnected;
endRead(new ArraySegment<byte>());
return;
}
// Get the length of the data that follows
int length = BitConverter.ToInt32(headerBufferSegment.Array, headerBufferSegment.Offset);
// Check the length
if (length > MaxFileSize)
{
// disconnect
endRead(new ArraySegment<byte>());
return;
}
// Read bytes specified in length.
EasySocketReader.ReadFromSocket(socket, length, (dataBufferSegment) =>
{
// if the ReadFromSocket returns 0, the socket is closed.
if (dataBufferSegment.Count == 0)
{
endRead(new ArraySegment<byte>());
return;
}
endRead(dataBufferSegment);
});
});
}
The EasySocketReader class can be found on my blog: http://csharp.vanlangen.biz/network-programming/async-sockets/asyncsocketreader/
The original EasyPacketReader can be found here: http://csharp.vanlangen.biz/network-programming/async-sockets/easypacketreader/
For the sending part, you could use something like this:
private void SendFile(Socket socket, string filename)
{
byte[] filenameData = Encoding.UTF8.GetBytes(filename);
socket.Send(BitConverter.GetBytes(filenameData.Length));
socket.Send(filenameData);
int fileSize;
byte[] fileData;
using (FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
fileSize = (int)stream.Length;
if (fileSize > MaxFileSize)
throw new ArgumentOutOfRangeException("File too big");
fileData = new byte[fileSize];
stream.Read(fileData, 0, fileSize);
}
socket.Send(BitConverter.GetBytes(fileSize));
socket.Send(fileData);
}

Categories

Resources