Alright so for my game, Ive set up a server / client peer to peer connection, to send positions and etc back and forth.
Although my messages arent actually sending that fast, and not reliably either. As in parts of the strings are missing, and sometimes the sending just halts and the thread doesnt continue ( not sure why ).t
Anyways my Recieving code is here :
public void RecieveAsync()
{
if (netStream == null) netStream = Server.GetStream();
if (netStream.DataAvailable == false) return;
netStream.BeginRead(ReadBuffer, 0, ReadBuffer.Length, new AsyncCallback(recieveCallBack), netStream);
}
public void recieveCallBack(IAsyncResult ar)
{
//try
//{
String content = String.Empty;
Console.WriteLine("Stuck trying to get data");
int rec = netStream.EndRead(ar);
if (rec > 0)
{
Console.WriteLine(Encoding.ASCII.GetString(
ReadBuffer, 0, rec));
string packet = Encoding.ASCII.GetString(
ReadBuffer, 0, rec);
bool completedPacket = false;
int appendTo = rec;
if (packet.Contains("<eof>"))
{
appendTo = packet.IndexOf("<eof>");
packet.Replace("<eof>", "");
completedPacket = true;
}
SB.Append(packet, 0, appendTo);
// Check for end-of-file tag. If it is not there, read
// more data.
content = SB.ToString();
if (completedPacket)
{
// All the data has been read from the
// client. Display it on the console.
if (DataRecieved != null)
{
string RecievedData = SB.ToString();
DataRecieved(RecievedData);
netStream.Flush();
Array.Clear(ReadBuffer, 0, ReadBuffer.Length);
ReadBuffer = new byte[1024];
}
SB.Clear();
// Echo the data back to the client.
}
else
{
// Not all data received. Get more.
Array.Clear(ReadBuffer, 0, ReadBuffer.Length);
ReadBuffer = new byte[1024];
netStream.BeginRead(ReadBuffer, 0, ReadBuffer.Length, recieveCallBack, netStream);
}
}
}
And my sending code here :
public void Send(byte[] data, int index, int length)
{
//add data as state
//socket.NoDelay = true;
if (netStream == null) netStream = TcpClient.GetStream();
netStream.BeginWrite(data, 0, length, sendCallback, netStream);
}
private void sendCallback(IAsyncResult ar)
{
//try
//{
netStream.EndWrite(ar);
//if (ar.AsyncState != null)
//{
// byte[] buffer = (byte[])ar.AsyncState;
// socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, sendCallback, null);
// return;
//}
if (OnSend != null)
{
OnSend(this);
}
netStream.Flush();
//catch (Exception ex)
//{
// System.Windows.Forms.MessageBox.Show(ex.ToString());
// return;
//}
}
The packets are under the Encoding.ASCII.Getbytes.
And both the server and client are updating in while (true) threads with a Thread.Sleep(1).
Because you're trying to reconstitute a string bit by bit (this approach will break if you use more common multibyte encoding such as UTF8), your approach to this is fragile.
As stated in my comment, you might well miss your <eof> because it is split over two reads.
IMO, a preferable approach is to tag your message with a preceding length field (4 byte int) so that you don't have to tiptoe around at the end of the message trying to figure out if it's finished yet.
Just pour all your reads into a MemoryStream until you reach the indicated message length, then decode the contents of the MemoryStream with whatever encoding you see fit.
Related
I know it sounds simple but I got some trouble with it. I am trying to make a system with a pic Microcontroller (MCU) and an xamarin android app. The sending part from app to the pic MCU is solved but when I want to send data from the MCU to the app it won't go as flaweless. I am using a HC-06 as a bluetooth device for receiving and sending messages.
The code for receiving from the MCU to the app is:
public void beginListenForData()
{
try
{
inStream = btSocket.InputStream;
}
catch (IOException ex)
{
Console.WriteLine(ex.Message);
}
Task.Factory.StartNew(() => {
byte[] buffer = new byte[1024];
int bytes;
while (true)
{
try
{
Array.Reverse(buffer, 0, buffer.Length);
bytes = inStream.Read(buffer, 0, buffer.Length);
if (bytes > 0)
{
string valor = Encoding.ASCII.GetString(buffer);
System.Diagnostics.Debug.WriteLine(buffer);
System.Diagnostics.Debug.WriteLine(bytes);
System.Diagnostics.Debug.WriteLine(valor);
if (valor == "D0O")
{
System.Diagnostics.Debug.WriteLine("Vergelijking gelukt!");
break;
}
//Result.Text = Result.Text + "\n" + valor;
}
}
catch (Java.IO.IOException)
{
//Result.Text = string.Empty;
break;
}
}
});
}
As you perhaps could geuss the message I try to sent from the MCU is D0O (valor) when the comparison worked with the incoming message I want to debug write that is was successful with:
System.Diagnostics.Debug.WriteLine("Vergelijking gelukt!");
The next part is for checking what for data is coming in:
System.Diagnostics.Debug.WriteLine(buffer);
System.Diagnostics.Debug.WriteLine(bytes);
System.Diagnostics.Debug.WriteLine(valor);
What I noticed is the strange output (see image):
As you can see the message is cut into 2 parts every time. Does anyone has any idea why and how to solve it?
I did change the array order with:
Array.Reverse(buffer, 0, buffer.Length);
Because I did notice it entered in the wrong order. This did work to put it in the right order.
Little update:
I changed some line of code and it works more "flaweless"
while ((count = inStream.Read(buffer, 0, buffer.Length)) > 0)
But what is strange that the first bit gets sepparated from the rest of the receiving string. I am not sure what causes this problem if anyone has a idea?
Thanks in advance.
I found a solution for the problem I was facing. So I will share my answer and thought process so perhaps other people can use the same.
So what I thought was there is a receiving buffer that saves the incoming char's. If the buffer is read with streamReader.Read it returns an integer of the readed char's. So I made second buffer of the datatype string[].
If the string[0] is empty I would place in my first Char that was read by the streamReader.Read. If the string[0] is NOT empty it means that the first char is already been read so I put the incoming char into string[1]. This means that the message that was split up is now into string[0] and string[1]. So what if I could combine it and save it into a string variable. This was done by: string eindtekst = string.Join("", buf); and this gives me the string in one piece so I can compare it. It is importent to clear the both array's as you're done with the comparing otherwise there would be new data added. And as you perhaps can tell string[0] == null would never be true. So only string[1] get's overridden al the time and that means you're losing out on data.
public void beginListenForData()
{
try
{
inStream = btSocket.InputStream;
streamReader = new StreamReader(inStream);
}
catch (IOException ex)
{
Console.WriteLine(ex.Message);
}
char[] buffer = new char[256];
string[] buf = new string[2];
int bytes;
while (1)
{
try
{
if ((bytes = streamReader.Read(buffer, 0, buffer.Length)) > 0)
{
string tekst = new string(buffer, 0, bytes);
if(buf[0] == null)
{
buf[0] = tekst;
}
else
{
buf[1] = tekst;
}
string eindtekst = string.Join("", buf);
if (eindtekst == "D0O")
{
System.Diagnostics.Debug.WriteLine("Vergelijking gelukt!");
System.Diagnostics.Debug.WriteLine(eindtekst);
Array.Clear(buffer, 0, buffer.Length);
Array.Clear(buf, 0, buf.Length);
writeData("D2O");
}
streamReader.DiscardBufferedData();
}
}
catch (Java.IO.IOException)
{
break;
}
}
}
Thanks for all the help
Currently I am working on a little project which should work over the network. But I have a problem with a read method, which should read bytes from a network stream. The function reads each single bytes and when it comes to a specific byte(in my case it is ! = 33) it fires an data received event. However when the server sends several messages in a short time the read method misses some messages. Here my code:
public void Read()
{
while (this.isReading == true)
{
try
{
if (!this.stream.DataAvailable)
{
Thread.Sleep(10);
continue;
}
List<byte> receivedBytes = new List<byte>();
byte[] buffer = new byte[1];
while (this.stream.DataAvailable)
{
this.stream.Read(buffer, 0, 1);
// Checks if the current byte is the last byte of a protocol
if (buffer[0] == 33)
{
break;
}
receivedBytes.Add(buffer[0]);
}
this.FireOnDataReceived(receivedBytes.ToArray());
}
catch
{
this.FireOnConnectionLost();
}
}
}
I am reading a .bin file and writing it into a Stream. Later, I am reading that stream object and then writing it into a Network Stream. Code is as following:
public async Task<bool> UploadFirmware(Stream _stream)
{
bool success = false;
try
{
_tcpclient = new TcpClient();
_tcpclient.Connect(_deviceip, port);
_stream.Seek(0, SeekOrigin.Begin);
m_NetworkStream = _tcpclient.GetStream();
byte[] buffer = new byte[1024];
m_ReadBuffer = new byte[1024];
int readcount = 0;
m_NetworkStream.BeginRead(m_ReadBuffer, 0, m_ReadBuffer.Length, new AsyncCallback(EndReceive), null);
await Task.Run(() =>
{
while ((readcount = _stream.Read(buffer, 0, buffer.Length)) > 0)
{
m_NetworkStream.Write(buffer, 0, readcount);
m_NetworkStream.Flush();
}
});
success = true;
}
catch (Exception ex)
{}
return success;
}
Normally, this code works fine, but sometimes on an IP Address, the code gets stuck at m_NetworkStream.Write(buffer, 0, readcount);. The thing is, I am updating the status in UI based on success value, but the code gets hanged at above mentioned line and doesn't come out at all. No exception is thrown at all to identify the issue. So, in UI the status is not updated, and unexpected result is produced. I am not able to identify the issue. Help of any kind will be highly appreciated.
EDIT:
Also, I have to do an operation in parallel. The code for EndReceive is as follows:
private void EndReceive(IAsyncResult ar)
{
try
{
int nBytes;
nBytes = m_NetworkStream.EndRead(ar);
if (nBytes > 0)
{
string res = Encoding.UTF8.GetString(m_ReadBuffer, 0, nBytes);
DeviceStatus status = new DeviceStatus();
string[] readlines = res.Split(new string[] { CRLF }, StringSplitOptions.RemoveEmptyEntries);
foreach (string readline in readlines)
{
if (readline.StartsWith("CODE"))
{
status.code = Convert.ToInt32(readline.Replace("CODE=", ""));
break;
}
}
status.deviceip = this._deviceip;
status.port = this.port;
status.DeviceID = this._DeviceID;
status.FirmwareID = this._FirmwareID;
status.FilePath = this._Path;
StatusUpdate(status);
m_ReadBuffer = new byte[1024];
}
}
catch (ObjectDisposedException ods)
{
return;
}
if (_tcpclient.Connected)
m_NetworkStream.BeginRead(m_ReadBuffer, 0, m_ReadBuffer.Length, new AsyncCallback(EndReceive), null);
}
I'm not sure you should have a while loop in order to write bytes read from a file (from disk) to a network stream ... you can just read all the bytes and write to the stream and flush in one move.
You can also add a write timeout to specify how much time can pass before the stream write operation fails, to prevent any possibility of 'hanging'.
With these modifications, the code would look something like this:
// make the tcp connection to the remote endpoint
_tcpclient = new TcpClient();
_tcpclient.Connect(_deviceip, port);
// read the file bytes in one operation
var allBytes = File.ReadAllBytes(fileNameOnDisk);
// get the network stream
m_NetworkStream = _tcpclient.GetStream();
// wait a max of 500ms for the write operation to happen
m_NetworkStream.WriteTimeout = 500;
// write the file bytes to the stream and flush without while/stream/seek etc.
m_NetworkStream.Write(allBytes, 0, allBytes.Length);
m_NetworkStream.Flush();
And when you've finished with the stream:
m_NetworkStream.Close();
m_NetworkStream.Dispose();
It seem odd that you starting to read from network stream (m_NetworkStream.BeginRead(...)) and right away in another thread starting to write into same stream (m_NetworkStream.Write(...)). I would suggest to finish reading first and then start writing. Also you could use Stream.CopyTo to copy data between streams.
public async Task<bool> UploadFirmware(Stream fileStream, IPEndPoint deviceEP)
{
bool success = false;
try
{
TcpClient client = new TcpClient();
client.Connect(deviceEP);
NetworkStream networkStream = client.GetStream();
BeginReadFromDevice(networkStream);
// send bin data to device
await fileStream.CopyToAsync(networkStream);
success = true;
}
catch (Exception)
{
}
return success;
}
private void BeginReadFromDevice(Stream networkStream)
{
byte[] buffer = new byte[1024];
networkStream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(EndReceive), null);
}
I'm having some issues when I really stress test my networking code. Essentially once the socket is set up it calls this:
NetworkStream networkStream = mClient.GetStream();
networkStream.BeginRead(buffer, 0, buffer.Length, ReadCallback, buffer);
private void ReadCallback(IAsyncResult result)
{
try
{
int read;
NetworkStream networkStream;
try
{
networkStream = mClient.GetStream();
read = networkStream.EndRead(result);
}
catch
{
return;
}
if (read == 0)
{
//The connection has been closed.
return;
}
var readBuffer = (byte[])result.AsyncState;
var readCount = readBuffer.Length;
while (readCount < 4)
{
readCount += networkStream.Read(readBuffer, 0, readBuffer.Length - readCount);
}
var length = BitConverter.ToInt32(readBuffer, 0);
var messageBuffer = new byte[length];
readCount = 0;
while (readCount < length)
{
readCount += networkStream.Read(messageBuffer, 0, messageBuffer.Length - readCount);
}
else
{
RaiseMessageReceived(this, messageBuffer);
}
//Then start reading from the network again.
readBuffer = new byte[4]; //may not need to reset, not sure
networkStream.BeginRead(readBuffer, 0, readBuffer.Length, ReadCallback, readBuffer);
}
catch(Exception)
{
//Connection is dead, stop trying to read and wait for a heal to retrigger the read queue
return;
}
}
Then the below is my send methods
private byte[] GetMessageWithLength(byte[] bytes)
{
//Combine the msg length to the msg
byte[] length = BitConverter.GetBytes(bytes.Length);
var msg = new byte[length.Length + bytes.Length];
Buffer.BlockCopy(length, 0, msg, 0, length.Length);
Buffer.BlockCopy(bytes, 0, msg, length.Length, bytes.Length);
return msg;
}
public override bool Send(byte[] bytes)
{
lock (sendQueue)
{
sendQueue.Enqueue(bytes);
Interlocked.Increment(ref sendQueueSize);
}
if (!mClient.Connected)
{
if (Connect())
{
RaiseConnectionChanged(this, true, Localisation.TCPConnectionEstablished);
}
else
{
RaiseConnectionChanged(this, false, (bytes.Length > 0 ? Localisation.TCPMessageFailed : Localisation.TCPMessageConnectionLost));
}
}
try
{
NetworkStream networkStream = mClient.GetStream();
lock (sendQueue)
{
if (sendQueue.Count == 0)
{
return true;
}
bytes = sendQueue.Dequeue();
}
var msg = GetMessageWithLength(bytes);
//Start async write operation
networkStream.BeginWrite(msg, 0, msg.Length, WriteCallback, null);
}
catch (Exception ex)
{
RaiseConnectionChanged(this, false, (bytes.Length > 0 ? Localisation.TCPMessageFailed : Localisation.TCPMessageConnectionLost));
}
return true;
}
/// <summary>
/// Callback for Write operation
/// </summary>
/// <param name="result">The AsyncResult object</param>
private void WriteCallback(IAsyncResult result)
{
try
{
NetworkStream networkStream = mClient.GetStream();
while (sendQueue.Count > 0)
{
byte[] bytes;
lock (sendQueue)
{
if (sendQueue.Count == 0)
{
break;
}
bytes = sendQueue.Dequeue();
}
var msg = GetMessageWithLength(bytes);
networkStream.Write(msg, 0, msg.Length);
Interlocked.Decrement(ref sendQueueSize);
}
networkStream.EndWrite(result);
mLastPacketSentAt = Environment.TickCount;
Interlocked.Decrement(ref sendQueueSize);
}
catch (Exception ex)
{
RaiseConnectionChanged(this, false, Localisation.TCPMessageConnectionLost);
}
}
But yea, at some point when I stress test the system (say 500 or so clients sending lots of messages at once), I notice maybe 1 packet in every 4 million to just not get recieved. I'm not sure if the issue lies in the sending or the recieving, which is why I have included both methods. However I will point out that if I choose to send another packet from the client, it still sends and receives correctly, so it is not just queued or something.
Can anyone see something I am missing?
The two read loops (e.g. while (readCount < length)) are buggy. You always read at offset zero. You should read at an ever-increasing offset.
This lead to overwriting of already-read data.
Also, I'm not sure if it is a good idea to mix synchronous and asynchronous reads. You lose the benefit of asynchronous code that way and still have to deal with callbacks and such. I think you should decide on one style and stick to it.
I have a simple tcp/ip chat program with a server and client. The first time I send a packet, it makes it to the client but during the NetworkStream.Read it stops execution and doesn't throw an exception. The next packet I send is read and processed perfectly. Another weird thing I noticed is that MyNetworkStream.DataAvailable is always false even if I get information from the server so I have to put a debug symbol and skip over it. I wish I could post all my code but it is long so I will post where I read and write to the network stream.
public void Listen(int byteLength)
{
var buffer = new byte[byteLength];
MySocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(Read), buffer);
}
private void Read(IAsyncResult ar)
{
while (MySocket.Connected)
{
MyNetworkStream = new NetworkStream(MySocket);
var buffer = new byte[((byte[])ar.AsyncState).Length];
if (!MyNetworkStream.DataAvailable)
throw new Exception("Data not available");
MyNetworkStream.Read(buffer, 0, buffer.Length); <------Here it stops execution without throwing an exception
string content = Encoding.ASCII.GetString(buffer);
if(OnRead == null)
continue;
var e = new CommandEventArgs( null, content);
Control target = null;
if (OnRead.Target is Control)
target = (Control)OnRead.Target;
if (target != null && target.InvokeRequired)
target.Invoke(OnRead, this, e);
else
OnRead(this,e);
}
}
public void Write(string message)
{
try
{
var buffer = Encoding.ASCII.GetBytes(message);
MySocket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, null, null);
if (OnWrite != null)
{
var target = (Control)OnWrite.Target;
if (target != null && target.InvokeRequired)
{
target.Invoke(OnWrite, this, new EventArgs());
}
else
{
OnWrite(this, new EventArgs());
}
}
}
catch
{
}
}
BeginReceive asynchronously waits for a message and fills your buffer. You then start synchronously reading from the socket, overwriting the first message in the process.
You should call EndReceive which returns the number of bytes read, then process your buffer before trying to read more bytes.
I'm not sure if it's directly related to the problem, but you are using the Read method wrong. You are reading data into the buffer, but you are ignoring how much data was actually read assuming that the Read call always returns as much data as you request, so you are decoding the entire buffer eventhough it might not be completely filled.
Get the return value of the Read call so that you know how much of the buffer is actually filled with data:
int len = MyNetworkStream.Read(buffer, 0, buffer.Length);
string content = Encoding.ASCII.GetString(buffer, 0, len);
You need to implement EndRecieve to get the complete data from the stream. Checkout the following example from MSDN :
public static void Read_Callback(IAsyncResult ar){
StateObject so = (StateObject) ar.AsyncState;
Socket s = so.workSocket;
int read = s.EndReceive(ar);
if (read > 0) {
so.sb.Append(Encoding.ASCII.GetString(so.buffer, 0, read));
s.BeginReceive(so.buffer, 0, StateObject.BUFFER_SIZE, 0,
new AsyncCallback(Async_Send_Receive.Read_Callback), so);
}
else{
if (so.sb.Length > 1) {
//All of the data has been read, so displays it to the console
string strContent;
strContent = so.sb.ToString();
Console.WriteLine(String.Format("Read {0} byte from socket" +
"data = {1} ", strContent.Length, strContent));
}
s.Close();
}
}