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
Related
I am a complete beginner in the TCP section, I try to program a Master Server which should handle more then 500 clients with small delay.
This is my first attempt, do you have any suggestions how to improve the code, or is my code complete garbage! :D
I send a Uint16 first as indicator of the message size
// receive Code!
private byte[] indexBuffer = new byte[sizeof(UInt16)];
private int indexSize = sizeof(UInt16);
public async void receiveData(TcpClient client) {
var result = await Task.Run(() => {
try {
int checkSum = client.Client.Receive(indexBuffer, 0, indexBuffer.Length, SocketFlags.None);
if (checkSum != indexSize) return null;
int packageSize = BitConverter.ToUInt16(indexBuffer, 0);
Console.WriteLine(packageSize);
var recData = new Byte[packageSize];
checkSum = client.Client.Receive(recData, 0, packageSize, SocketFlags.None);
if (checkSum != packageSize) return null;
return Encoding.ASCII.GetString(recData);
} catch(Exception ex) {
Console.WriteLine(ex.Message);
return "-1";
}
});
// blabla do something
Console.WriteLine(result);
//---------------------
if (client.Connected)
receiveData(client);
}
IOCP server is good choice in this case.
There are many samples for this.
May be this one is good.
https://www.codeproject.com/Articles/832818/EpServerEngine-cs-A-lightweight-asynchronous-IOCP
Good luck.
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.?
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
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 just noticed that my socket client wasn't receiving the same data the server was sending back to it. The text gets cut off after 8192 characters.
Is there some limit I am not aware of? How do I get past this?
The client uses this code:
//Send and Receive
public string sendAndReceiveMSG(string msg)
{
try
{
NetworkStream serverStream = clientSocket.GetStream();
string sendresponse = sendMSG(msg, serverStream);
if (sendresponse == "ConnectionCrash")
{
return sendresponse;
}
else if (sendresponse == "OK")
{
string receiveresponse = receiveMSG(serverStream);
return receiveresponse;
}
return "UnknownErrorInternal";
}
catch (Exception ex)
{
return "UnknownErrorInternal";
}
}
//Send msg
private string sendMSG(string msg, NetworkStream serverStream)
{
try
{
byte[] outStream = System.Text.Encoding.ASCII.GetBytes(msg);
serverStream.Write(outStream, 0, outStream.Length);
serverStream.Flush();
return "OK";
}
catch (Exception ex)
{
endSock();
return "ConnectionCrash";
}
}
//Receive msg
private string receiveMSG(NetworkStream serverStream)
{
try
{
byte[] inStream = new byte[10025];
int buffSize = clientSocket.ReceiveBufferSize;
dynamic bytesRead = serverStream.Read(inStream, 0, buffSize);
string returndata = System.Text.Encoding.ASCII.GetString(inStream, 0, bytesRead);
return returndata;
}
catch (Exception ex)
{
endSock();
return "ConnectionCrash";
}
}
The client then gets a response from the server like so;
string recv = client.sendAndReceiveMSG("someRequest");
You have only processed one call to Read. This behaviour is entirely expected; you very rarely get all the data in a single packet (frankly I'm amazed you didn't notice it sooner).
You need to decide on a "framing" policy (i.e. how you distinguish each sub-message - maybe new lines if text based, or length-prefix for binary) - and obtain a frames worth of data before processing. This usually means calling Read in a loop, or (for text) using something like a StreamReader which handles that for you (i.e. calling ReadLine() in a loop).
If there is only one message on the socket, and the caller closes their connection, you can dispense with framing, and just read until Read returns something non-positive (i.e. EOF).