I am trying to implement a system that can send and receive "Nessages" (a custom type) using async Sockets. Each Message consists of three elements:
First I send the Message-ID (4 bytes), next is the length of the data (4 bytes) and then the actual data.
The way TCP/IP works, I can not know if the full Message is in the buffer of data that I just received. I need to look for the InfoHeader (ID and length) first and use the remaining data to fill the Message's DataBuffer.
public void ReadCallback(IAsyncResult ar)
{
try
{
// How many bytes were received? They are now stored in the PacketBuffer
int bytesReceived = Socket.EndReceive(ar);
if (bytesReceived != 0)
{
// We did receive some data
if (MessageInfoHeader.Length < NetProtocol.NetInfoHeaderSize)
{
// The InfoHeader we have is not complete yet. How many bytes are missing from it?
int infoHeaderDataInCurrentBuffer = NetProtocol.NetInfoHeaderSize - (int) MessageInfoHeader.Length;
// Check if we have read enough data to fill the entire missing InfoHeader
if (infoHeaderDataInCurrentBuffer > bytesReceived)
{
// Nope, we dont. Fill as much as we can
infoHeaderDataInCurrentBuffer = bytesReceived;
Log.Info("We do not have enough data to complete the InfoHeader yet. Fill as much as we can");
}
else
{
Log.Info("We do have enough data to complete the InfoHeader");
}
// Now fill it from the chunk of data we just received
MessageInfoHeader.Write(ReceivedData, 0, infoHeaderDataInCurrentBuffer);
// See if there is any data remaining in the buffer that we can store in the MessageDataBuffer
int dataRemainingInPacket = bytesReceived - infoHeaderDataInCurrentBuffer;
Log.Info("DataRemainingInPacket: " + dataRemainingInPacket);
// Check again if we have the full header
if (MessageInfoHeader.Length == NetProtocol.NetInfoHeaderSize)
{
Log.Info("We now have assembled the full InfoHeader");
// We do have the full InfoHeader. Use the rest of the data to fill the DataBuffer
using (MemoryStream ms = new MemoryStream())
{
byte[] b = MessageInfoHeader.GetBuffer();
ms.Write(b, 0, b.Length);
ms.Seek(0, SeekOrigin.Begin);
try
{
using (BinaryReader br = new BinaryReader(ms))
{
CurrentMessageID = br.ReadInt32();
CurrentMessageDataLength = br.ReadInt32();
Log.Info("InfoHeader: MessageID=" + CurrentMessageID + " / DataLength=" + CurrentMessageDataLength);
}
}
catch (Exception ex)
{
throw ex;
}
}
if (dataRemainingInPacket > 0)
{
Log.Info("There are " + dataRemainingInPacket + " bytes remaining in the packet. Writing them to the PacketDataBuffer");
MessageDataBuffer.Write(ReceivedData, CurrentPacketBytesRead, ReceivedData.Length - CurrentPacketBytesRead);
}
}
}
else
{
MessageDataBuffer.Write(ReceivedData, 0, ReceivedData.Length);
if(ReceivedData.Length <= NetDataBufferSize)
{
Log.Info("WE HAVE RECEIVED THE ENTIRE MESSAGE");
}
}
// Start receiving the new TCP-Packet
Socket.BeginReceive(ReceivedData, 0, ReceivedData.Length, SocketFlags.None, new AsyncCallback(ReadCallback), null);
}
else
{
Log.Info("No data has been received");
}
}
catch (Exception ex)
{
throw ex;
}
}
private void AcceptCallback(IAsyncResult ar)
{
// Retrieve the listening Socket
Socket listener = (Socket)ar.AsyncState;
// Retrieve the Socket that is actually connected to the client
Socket csocket = listener.EndAccept(ar);
Log.Info("Accepted connection from: " + csocket.RemoteEndPoint.ToString());
// Create a new client with the CSocket and add it to the list
ClientConnection client = ClientManager.AddClient(csocket);
// Start reading data from the Client's Socket and then enter the "read-loop" inside the client
client.Socket.BeginReceive(client.ReceivedData, 0, (int) client.ReceivedData.Length, SocketFlags.None, new AsyncCallback(client.ReadCallback), null);
// Turn the listener back into listening mode
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
}
public const int NetInfoHeaderSize = 8; // 2x int
public static byte[] FrameMessage(NetMessage message)
{
byte[] result;
using(MemoryStream ms = new MemoryStream())
{
using (BinaryWriter bw = new BinaryWriter(ms))
{
bw.Write(message.ID);
bw.Write(message.Data.Length);
bw.Write(message.Data);
}
result = ms.ToArray();
}
return result;
}
This piece of code obviously does not work correctly. I get the "RECEIVED ENTIRE MESSAGE" line multiple times.
Question: What exactly am I doing wrong? I'm failing to wrap my head around what is the best way to handle something like this? Thanks in advance for any input!
There could be quite a few problems. But the first one I can see for the loop on "RECEIVED ENTIRE MESSAGE" is that you are assuming the ReceivedData buffer has been filled entirely by Socket.EndReceive(ar); - which isn't the case, so a first troubleshooting start could be to rewrite this:
MessageDataBuffer.Write(ReceivedData, 0, ReceivedData.Length);
if (ReceivedData.Length <= NetDataBufferSize)
{
Log.Info("WE HAVE RECEIVED THE ENTIRE MESSAGE");
}
to:
MessageDataBuffer.Write(ReceivedData, 0, bytesReceived);
if (MessageDataBuffer.Length <= NetDataBufferSize)
{
Log.Info("WE HAVE RECEIVED THE ENTIRE MESSAGE");
}
Assuming that MessageDataBuffer is intended to contain the entire message
Related
I tried to receive data from the windows program Termite on my Xamarin program through bluetooth. This is the code I used for receiving data:
public async Task BeginListenForData()
{
try
{
inStream = btSocket.InputStream;
streamReader = new StreamReader(inStream);
}
catch (IOException ex)
{
Console.WriteLine(ex.Message);
}
char[] buffer = new char[256];
int bytes;
await Task.Run(async () =>
{
while (true)
{
try
{
if ((bytes = await streamReader.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
buffer = new Char[(int)streamReader.BaseStream.Length];
streamReader.Read(buffer, 0, (int)streamReader.BaseStream.Length);
System.Diagnostics.Debug.WriteLine(new String(buffer));
string eindtekst = new string(buffer, 0, bytes);
streamReader.DiscardBufferedData();
}
}
catch (Java.IO.IOException)
{
break;
}
}
}).ConfigureAwait(false) ;
return;
}
But when I used breakpoint it receives my message most of the time in two parts. For example the string "Received", it received first the "R" and than the rest of the string "eceived". Is there a way to receive the message as one part?
This code part: bytes = await streamReader.ReadAsync(buffer, 0, buffer.Length is where bytes is first 1 and than 7 with the example of the string "Received".
Within an other question I posted about an other problem I solved this problem with it. I posted my answer on the other page, so I will leave a link to the other page about how to receive data within Xamarin with bluetooth.
How to receive data with bluetooth in xamarin
Thanks for all help given
i have the following code executed by a listening Thread. What it does: Reading the first Message as the total message length then assemble all packets to a big data array. (Im sending images) It all works as intended.
But after the first image is recieved and the function is done. ("ImageLengthResetted" gets printed) It closes the connection. I think this is due the fact i am running out of the scope from:
using(connectedTcpClient = tcpListener.AcceptTcpClient())
and thats what kills the connection. How can i keep this connection open?
Adding another
while(true)
after i've been connected wont do the trick. As well as executing the while loop completle after the using statments.
private void ListenForIncommingRequests()
{
try
{
// Create listener on localhost port 8052.
localAddr = IPAddress.Parse(IPadrr);
Debug.Log(localAddr);
tcpListener = new TcpListener(localAddr, port);
Debug.Log("Before Init tcplistern");
tcpListener.Start();
Debug.Log("Server is listening");
Byte[] dataRecieved = new Byte[SEND_RECIEVE_COUNT];
while (true)
{
using (connectedTcpClient = tcpListener.AcceptTcpClient())
{
Debug.Log("Accepted TCP Client");
// Get a stream object for reading
using (NetworkStream stream = connectedTcpClient.GetStream())
{
int length;
Debug.Log("Accepted Stream");
// Read incomming stream into byte arrary.
while ((length = stream.Read(dataRecieved, 0, dataRecieved.Length)) != 0)
{
Debug.Log("receiving Loop lengt: " + length);
counterReceived++;
//Get Message length with first message
if (messageLength == 0)
{
messageLength = System.BitConverter.ToInt32(dataRecieved, 0);
data = new byte[messageLength];
messageJunks = messageLength / SEND_RECIEVE_COUNT;
restMessage = messageLength % SEND_RECIEVE_COUNT;
junkCounter = 0;
}
else
{
if (junkCounter < messageJunks)
{
Array.Copy(dataRecieved, 0, data, junkCounter * SEND_RECIEVE_COUNT, SEND_RECIEVE_COUNT);
junkCounter++;
}
else
{
Array.Copy(dataRecieved, 0, data, junkCounter * SEND_RECIEVE_COUNT, restMessage);
//Whole Message recieved, reset Message length
messageLength = 0;
readyToDisplay = true;
Debug.Log("ImageLengthResetteed");
}
}
}
}
}
}
}
catch (Exception socketException)
{
Debug.Log("SocketException " + socketException.ToString());
}
}
Client Side opens send Thread with following function where socketConnection gets globally initialized on the receiving thread of the client:
private void sendData(byte[] data)
{
try
{
//socketConnection = new TcpClient(IPadrr, port);
using (NetworkStream stream = socketConnection.GetStream())
{
//Prepare the Length Array and send first
byte[] dataLength = BitConverter.GetBytes(data.Length);
int packagesSend = 0;
int numberPackages = data.Length / SEND_RECIEVE_COUNT;
if (stream.CanWrite)
{
for (counter = 0; counter <= data.Length; counter += SEND_RECIEVE_COUNT)
{
if (counter == 0)
{
stream.Write(dataLength, 0, dataLength.Length);
}
if (packagesSend < numberPackages)
{
stream.Write(data, counter, SEND_RECIEVE_COUNT);
Thread.Sleep(20);
packagesSend++;
}
else
{
stream.Write(data, counter, data.Length % SEND_RECIEVE_COUNT);
Debug.Log("FINDISCHD");
}
}
}
}
}
catch (Exception err)
{
print(err.ToString());
}
}
Im glad for any help!
The Problem was on the Client Side. I initialized the
NetworkStream stream;
now globally in the same function the socketConnection gets init.
I have a function to request an update from the server. I provide the query and also indicate the expected length of the response.
public Byte[] GetUpdate(Byte[] query, int expLength)
{
var response = new Byte[expLength];
lock(Client)
{
Stream s = Client.GetStream();
s.Write(query, 0, query.Length);
var totalBytesRead = 0;
var numAttempts = 0;
while(totalBytesRead < expLength && numAttempts < MAX_RETRIES)
{
numAttempts++;
int bytes;
try
{
bytes = s.Read(response, totalBytesRead, expLength);
}
catch (Exception ex)
{
throw new IOException();
}
totalBytesRead += bytes;
}
if(totalBytesRead < expLength)
{
// should probably throw something here
throw new IOException();
}
}
return response;
}
The function that calls the above function is given below. Both of them belong to class Connection.
public Byte[] GetData(string ip, int port ,Byte [] query, int responseLen)
{
Connection connection = GetConnection(ip,port);
Byte[] data = null;
try
{
data = connection.GetUpdate(query, responseLen);
}
catch(Exception e)
{
connection?.Disconnect();
return new Byte[0];
}
return data;
}
My question is as follows.
With the above code I am trying to read some values of a remote network endpoint. Sometimes the connections go down on the link. I test the scenario by manually unplugging the Ethernet cable. Once I unplug and plug the cable I sometimes find that s.Read() in function GetUpdate throws StreamReadFailed exception.It happens occasionally. What could be the possible reason for this and what is the best way to recover from this.?
Consider the following code:
internal class Program
{
private static void Main(string[] args)
{
var client = new TcpClient();
client.ConnectAsync("localhost", 7105).Wait();
var stream = client.GetStream();
var observable = stream.ReadDataObservable().Repeat();
var s = from d in observable.Buffer(4)
let headerLength = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(d.ToArray(), 2))
let b = observable.Take(headerLength)
select b.ToEnumerable().ToArray();
s.Subscribe(a => Console.WriteLine("{0}", a));
Console.ReadLine();
}
}
public static class Extensions
{
public static IObservable<byte> ReadDataObservable(this Stream stream)
{
return Observable.Defer(async () =>
{
var buffer = new byte[1024];
var readBytes = await stream.ReadAsync(buffer, 0, buffer.Length);
return buffer.Take(readBytes).ToObservable();
});
}
}
Basically I want to parse the messages I receive with Reactive Extensions. The header of the message is parsed correctly using the Buffer(4) and I get the length of the remainder of the message. The problem that arises is that when I do stream.Take(headerLength), the code reevaluates the whole "chain" and tries to get a new message from the stream instead of returning the rest of the bytes which already has been read from the stream. To be more exact, the first ReadAsync(...) returns 38 bytes, the Buffer(4) returns the first 4 of those, the observable.Take(headerLength) does not return the remainding 34 bytes but instead tries to read a new message with ReadAsync.
The question is, how can I make sure the observable.Take(headerLength) receives the already read 34 bytes and not try to read a new message from the stream? I've searched around for a solution, but I can't really figure out how to achieve this.
Edit: This solution (Using Reactive Extensions (Rx) for socket programming practical?) is not what I'm looking for. This isn't reading everything available in the stream (up to buffersize) and makes a continous bytestream out of it. To me this solution doesn't seem like a very efficient way to read from a stream, hence my question.
This approach isn't going to work. The problem is the way you are using the observable. Buffer will not read 4 bytes and quit, it will continually read 4 byte chunks. The Take forms a second subscription that will read overlapping bytes. You'll find it much easier to parse the stream directly into messages.
The following code makes a good deal of effort to clean up properly as well.
Assuming your Message is just this, (ToString added for testing):
public class Message
{
public byte[] PayLoad;
public override string ToString()
{
return Encoding.UTF8.GetString(PayLoad);
}
}
And you have acquired a Stream then you can parse it as follows. First, a method to read an exact number of bytes from a stream:
public async static Task ReadExactBytesAsync(
Stream stream, byte[] buffer, CancellationToken ct)
{
var count = buffer.Length;
var totalBytesRemaining = count;
var totalBytesRead = 0;
while (totalBytesRemaining != 0)
{
var bytesRead = await stream.ReadAsync(
buffer, totalBytesRead, totalBytesRemaining, ct);
ct.ThrowIfCancellationRequested();
totalBytesRead += bytesRead;
totalBytesRemaining -= bytesRead;
}
}
Then the conversion of a stream to IObservable<Message>:
public static IObservable<Message> ReadMessages(
Stream sourceStream,
IScheduler scheduler = null)
{
int subscribed = 0;
scheduler = scheduler ?? Scheduler.Default;
return Observable.Create<Message>(o =>
{
// first check there is only one subscriber
// (multiple stream readers would cause havoc)
int previous = Interlocked.CompareExchange(ref subscribed, 1, 0);
if (previous != 0)
o.OnError(new Exception(
"Only one subscriber is allowed for each stream."));
// we will return a disposable that cleans
// up both the scheduled task below and
// the source stream
var dispose = new CompositeDisposable
{
Disposable.Create(sourceStream.Dispose)
};
// use async scheduling to get nice imperative code
var schedule = scheduler.ScheduleAsync(async (ctrl, ct) =>
{
// store the header here each time
var header = new byte[4];
// loop until cancellation requested
while (!ct.IsCancellationRequested)
{
try
{
// read the exact number of bytes for a header
await ReadExactBytesAsync(sourceStream, header, ct);
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception ex)
{
// pass through any problem in the stream and quit
o.OnError(new InvalidDataException("Error in stream.", ex));
return;
}
ct.ThrowIfCancellationRequested();
var bodyLength = IPAddress.NetworkToHostOrder(
BitConverter.ToInt16(header, 2));
// create buffer to read the message
var payload = new byte[bodyLength];
// read exact bytes as before
try
{
await ReadExactBytesAsync(sourceStream, payload, ct);
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception ex)
{
o.OnError(new InvalidDataException("Error in stream.", ex));
return;
}
// create a new message and send it to client
var message = new Message { PayLoad = payload };
o.OnNext(message);
}
// wrap things up
ct.ThrowIfCancellationRequested();
o.OnCompleted();
});
// return the suscription handle
dispose.Add(schedule);
return dispose;
});
}
EDIT - Very hacky test code I used:
private static void Main(string[] args)
{
var listener = new TcpListener(IPAddress.Any, 12873);
listener.Start();
var listenTask = listener.AcceptTcpClientAsync();
listenTask.ContinueWith((Task<TcpClient> t) =>
{
var client = t.Result;
var stream = client.GetStream();
const string messageText = "Hello World!";
var body = Encoding.UTF8.GetBytes(messageText);
var header = BitConverter.GetBytes(
IPAddress.HostToNetworkOrder(body.Length));
for (int i = 0; i < 5; i++)
{
stream.Write(header, 0, 4);
stream.Write(body, 0, 4);
stream.Flush();
// deliberate nasty delay
Thread.Sleep(2000);
stream.Write(body, 4, body.Length - 4);
stream.Flush();
}
stream.Close();
listener.Stop();
});
var tcpClient = new TcpClient();
tcpClient.Connect(new IPEndPoint(IPAddress.Loopback, 12873));
var clientStream = tcpClient.GetStream();
ReadMessages(clientStream).Subscribe(
Console.WriteLine,
ex => Console.WriteLine("Error: " + ex.Message),
() => Console.WriteLine("Done!"));
Console.ReadLine();
}
Wrapping up
You need to think about setting a timeout for reads, in case the server dies, and some kind of "end message" should be sent by the server. Currently this method will just continually tries to receive bytes. As you haven't specced it, I haven't included anything like this - but if you do, then as I've written it just breaking out of the while loop will cause OnCompleted to be sent.
I guess what is needed here is Qactive: A Rx.Net based queryable reactive tcp server provider
Server
Observable
.Interval(TimeSpan.FromSeconds(1))
.ServeQbservableTcp(new IPEndPoint(IPAddress.Loopback, 3205))
.Subscribe();
Client
var datasourceAddress = new IPEndPoint(IPAddress.Loopback, 3205);
var datasource = new TcpQbservableClient<long>(datasourceAddress);
(
from value in datasource.Query()
//The code below is actually executed on the server
where value <= 5 || value >= 8
select value
)
.Subscribe(Console.WriteLine);
What´s mind blowing about this is that clients can say what and how frequently they want the data they receive and the server can still limit and control when, how frequent and how much data it returns.
For more info on this https://github.com/RxDave/Qactive
Another blog.sample
https://sachabarbs.wordpress.com/2016/12/23/rx-over-the-wire/
I've asked about this topic before and thought I had a handle on it but I'm finding I'm missing something here. I've got some C code in linux that I'm sending data through a socket to my C# winforms visualization code. I'm sending the data from C as fast as I can calculate it which pretty damn fast. But in C# my datagridview is not updating correctly. If I slow down the rate at which I am sending the data to the c# code it does okay. But I can't really do that. I really am dying here.
So in C# this is what I have:
{
. . .
sListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sListener.Bind(new IPEndPoint(0, 1994));
Listen();
}
private void Listen()
{
sListener.Listen(10);
// Begins an asynchronous operation to accept an attempt
AsyncCallback aCallback = new AsyncCallback(AcceptCallback);
sListener.BeginAccept(aCallback, sListener);
}
public void AcceptCallback(IAsyncResult ar)
{
Socket listener = null;
// A new Socket to handle remote host communication
Socket handler = null;
try
{
// Receiving byte array
byte[] buffer = new byte[1024];
// Get Listening Socket object
listener = (Socket)ar.AsyncState;
// Create a new socket
handler = listener.EndAccept(ar);
// Using the Nagle algorithm
handler.NoDelay = false;
// Creates one object array for passing data
object[] obj = new object[2];
obj[0] = buffer;
obj[1] = handler;
// Begins to asynchronously receive data
handler.BeginReceive( buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), obj);
// Begins an asynchronous operation to accept an attempt
AsyncCallback aCallback = new AsyncCallback(AcceptCallback);
listener.BeginAccept(aCallback, listener);
}
catch (Exception exc) { MessageBox.Show(exc.ToString()); }
}
public void ReceiveCallback(IAsyncResult ar)
{
try
{
// Fetch a user-defined object that contains information
object[] obj = new object[2];
obj = (object[])ar.AsyncState;
// Received byte array
byte[] buffer = (byte[])obj[0];
// A Socket to handle remote host communication.
handler = (Socket)obj[1];
// Received message
string content = string.Empty;
// The number of bytes received.
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
Array.Resize(ref buffer, bytesRead);
double[] values = new double[buffer.Length / 8];
int i = 0;
values[i] = BitConverter.ToDouble(buffer, i * 8);
values[++i] = BitConverter.ToDouble(buffer, i * 8);
values[++i] = BitConverter.ToDouble(buffer, i * 8);
values[++i] = BitConverter.ToDouble(buffer, i * 8);
values[++i] = BitConverter.ToDouble(buffer, i * 8);
this.Invoke((MethodInvoker)delegate()
{
if (dataGridView1.Rows.Count > 5)
{
dataGridView1.Rows.RemoveAt(this.dataGridView1.Rows[5].Index);
}
dataGridView1.Rows[0].Cells[1].Value = values[0];
dataGridView1.Rows[1].Cells[1].Value = values[1];
dataGridView1.Rows[2].Cells[1].Value = values[2];
dataGridView1.Rows[3].Cells[1].Value = values[3];
dataGridView1.Rows[4].Cells[1].Value = values[4];
});
}
// Continues to asynchronously receive data
byte[] buffernew = new byte[1024];
obj[0] = buffernew;
obj[1] = handler;
handler.BeginReceive(buffernew, 0, buffernew.Length,
SocketFlags.None,
new AsyncCallback(ReceiveCallback), obj);
}
catch (Exception exc) { MessageBox.Show(exc.ToString()); }
}
Your async code is firing async, which is as expected... But this means that the order of processing could differ from the order of receive. For example:
.NET receive message 1
.NET receive message 2
.NET finish receive message 2
.NET finish receive message 1
Here you assumed you'd see 1, then 2 since that's the order they were received in, but NOT the order they finished being received in.
If the order of your data is important, you must either send all of it at once in a large batch (bad), or receive it sequentially (the underlying TCP should ensure that messages are delivered in the appropriate order).