I have a program that reads and writes a hexadecimal byte[] from SerialPort.
My program only use 5 bytes(five hexadecimal) in one communication.
The problem is that the DataReceived occurence cycle is random. So, sometimes it reads 5 bytes, sometimes it reads 4 bits.
I always want DataReceived to read 5 bytes. Is it possible?
Below code is the logic of program that I wrote.
serialPort.Write(sendData, 0, sendData.Length);
serialPort.DataReceived += (sender, e) =>
{
var receiveSize = serialPort.BytesToRead;
var buffer = new byte[receiveSize];
serialPort.Read(buffer, 0, buffer.Length);
this.Invoke(() =>
{
readRichTextBox.AppendText($"{string.Join(" ", Encoding.UTF8.GetString(buffer))}\n");
});
};
I solved it after creating a empty List<byte>. Is there a better way?
private List<byte> bytes = new List<byte>();
serialPort.DataReceived += (sender, e) =>
{
var receiveSize = serialPort.BytesToRead;
var buffer = new byte[receiveSize];
serialPort.Read(buffer, 0, buffer.Length);
this.Invoke(() =>
{
foreach (var b in buffer)
{
bytes.Add(b);
}
if (bytes.Count == 10)
{
readRichTextBox.AppendText($"{string.Join(" ", Encoding.UTF8.GetString(bytes.ToArray()))}\n");
bytes.Clear();
}
});
};
Related
Im trying to send an object( in my case an image) over a networkstream.. however- im not getting the full image..
This is the client code:
private void Form1_Load(object sender, EventArgs e)
{
TcpClient c = new TcpClient();
c.Connect("10.0.0.4", 10);
NetworkStream ns = c.GetStream();
Bitmap f = GetDesktopImage();
byte[] buffer = imageToByteArray(f);
byte[] len = BitConverter.GetBytes(buffer.Length);
MemoryStream stream = new MemoryStream();
stream.Write(len, 0, len.Length);
stream.Write(buffer, 0, buffer.Length);
stream.Position = 0;
stream.CopyTo(ns);
}
As you can see i write the entire content to a regular MemoryStream first(because i dont want to use twice the NetworkStream- only then, i copy the MemoryStream content into the NetworkStream.
The server code:
private void Form1_Load(object sender, EventArgs e)
{
TcpListener tl = new TcpListener(IPAddress.Any, 10);
tl.Start();
TcpClient c = tl.AcceptTcpClient();
network = new NetworkStream(c.Client);
byte[] buff = new byte[4];
network.Read(buff, 0, 4);
int len = BitConverter.ToInt32(buff, 0);
buff = new byte[len];
network.Read(buff, 0, buff.Length);
pictureBox1.Image = byteArrayToImage(buff);
Thread th = new Thread(method);
}
Now when i run both application im getting only the top part of the captured image... It's even more odd because writing directly both to a network stream works perfect... For example:
ns.Write(len, 0, len.Length);
ns.Write(buffer, 0, buffer.Length);
This would work fine and i'll get the full image in the other side.. but i dont want to use it twice(it's just an example, in my real project i would have to use it alot so i would like to reduce the network usage as much as posibble ,and not trigger it for every single data).
Why it's not working using simply the CopyTo method?
I would appreciate any help!
Thanks
In your server code you are ignoring the result of NetworkStream.Read which is the actual number of bytes read. This can be less than the number of bytes you actually requested. You need to keep calling Read until you have received all the bytes you need.
The differences you seeing between 1 or multiple writes has to do with the buffering/timing in the network stack. I suspect you just getting lucky receiving the image when doing a single write - this will not always be the case! You need to handle the result of Read as explained above.
Code Example:
void ReadBuffer(byte[] buffer, int offset, int count)
{
int num;
int num2 = 0;
do
{
num2 += num = _stream.Read(buffer, offset + num2, count - num2);
}
while ((num > 0) && (num2 < count));
if (num2 != count)
throw new EndOfStreamException
(String.Format("End of stream reached with {0} bytes left to read", count - num2));
}
I am trying to send some text over the network using sockets and memory streams. The full data length in my example is 20480 bytes long. Buffer size is 8192.
Before I can receive the last 4096 bytes, the socket receives only 3088 bytes and the whole thread exits without throwing an exception just before receiving the last chunk of data.
// Send
while (sentBytes < ms.Length)
{
if (streamSize < Convert.ToInt64(buffer.Length))
{
ms.Read(buffer, 0, Convert.ToInt32(streamSize));
count = socket.Send(buffer, 0, Convert.ToInt32(streamSize), SocketFlags.None);
sentBytes += Convert.ToInt64(count);
streamSize -= Convert.ToInt64(count);
}
else
{
ms.Read(buffer, 0, buffer.Length);
count = socket.Send(buffer, 0, buffer.Length, SocketFlags.None);
sentBytes += Convert.ToInt64(count);
streamSize -= Convert.ToInt64(count);
}
}
// Receive
while (readBytes < size)
{
if (streamSize < Convert.ToInt64(buffer.Length))
// exits after this, before receiving the last 1008 bytes
{
count = socket.Receive(buffer, 0, Convert.ToInt32(streamSize), SocketFlags.None);
if (count > 0)
{
ms.Write(buffer, 0, count);
readBytes += Convert.ToInt64(count);
streamSize -= Convert.ToInt64(count);
}
}
else
{
count = socket.Receive(buffer, 0, buffer.Length, SocketFlags.None);
if (count > 0)
{
ms.Write(buffer, 0, count);
readBytes += Convert.ToInt64(count);
streamSize -= Convert.ToInt64(count);
}
}
}
I use the exact same algorithm to send/receive files having bigger sizes (over 1 GB) and the transfer works perfectly, no files are corrupted (I use file streams for that).
Interestingly, this code works in the debugger if I add a breakpoint on the sender side.
Also works with this modification:
if (streamSize < Convert.ToInt64(buffer.Length))
{
if (count > 0)
{
ms.Write(buffer, 0, Convert.ToInt32(streamSize));
readBytes += streamSize;
streamSize -= streamSize;
}
}
but this comes with no checking on how much data is received and also doesn't work to transfer files.
Could anybody point it out what is going on here?
Thread started like this:
public ClientConnection(Socket clientSocket, Server mainForm)
{
this.clientSocket = clientSocket;
clientThread = new Thread(ReceiveData);
clientConnected = true;
this.mainForm = mainForm;
clientThread.Start(clientSocket);
}
Added from comment by OP
// text is 10240 characters long
MemoryStream ms = new MemoryStream(UnicodeEncoding.Unicode.GetBytes(text));
// streamsize is 20480, which is sent prior to text in a header to the receiver
long streamSize = ms.Length;
Update:
Tested with more files, now the file transfer fails as well. The problem is with the last 1008 bytes in all cases.
I found it... When I expected to receive the header, I hadn't prepare the software to receive exactly header sized data.
//byte[] buffer = new byte[1024];
byte[] buffer = new byte[16];
readBytes = socket.Receive(buffer, 0, buffer.Length, SocketFlags.None);
This somehow caused a rogue 16 bytes of data written on the socket every time I was receiving the last chunk of the payload, the socket disconnected and the thread exited not throwing any exceptions whatsoever. I hope this answer will help one day someone else running into the same issue. All data transfer works properly now.
Please consider the simplified implementation of the functionality using NetworkStream class to perform the I/O-operations instead of the Socket class: the NetworkStream class allows to slightly increase the level of abstraction. An instance of the NetworkStream class can be created using an instance of the Socket class.
Sender
The implementation of the Sender is pretty straightforward using the Stream.CopyTo Method:
private static void CustomSend(Stream inputStream, Socket socket)
{
using (var networkStream = new NetworkStream(socket))
{
inputStream.CopyTo(networkStream, BufferSize);
}
}
Receiver
Let's introduce the following extension methods for the Stream class which copies the exact number of bytes from one instance of the Stream class to another using the specified buffer:
using System;
using System.IO;
public static class StreamExtensions
{
public static bool TryCopyToExact(this Stream inputStream, Stream outputStream, byte[] buffer, int bytesToCopy)
{
if (inputStream == null)
{
throw new ArgumentNullException("inputStream");
}
if (outputStream == null)
{
throw new ArgumentNullException("outputStream");
}
if (buffer.Length <= 0)
{
throw new ArgumentException("Invalid buffer specified", "buffer");
}
if (bytesToCopy <= 0)
{
throw new ArgumentException("Bytes to copy must be positive", "bytesToCopy");
}
int bytesRead;
while (bytesToCopy > 0 && (bytesRead = inputStream.Read(buffer, 0, Math.Min(buffer.Length, bytesToCopy))) > 0)
{
outputStream.Write(buffer, 0, bytesRead);
bytesToCopy -= bytesRead;
}
return bytesToCopy == 0;
}
public static void CopyToExact(this Stream inputStream, Stream outputStream, byte[] buffer, int bytesToCopy)
{
if (!TryCopyToExact(inputStream, outputStream, buffer, bytesToCopy))
{
throw new IOException("Failed to copy the specified number of bytes");
}
}
}
So, the Receiver can be implemented as follows:
private static void CustomReceive(Socket socket)
{
// It seems your receiver implementation "knows" the "size to receive".
const int SizeToReceive = 20480;
var buffer = new byte[BufferSize];
var outputStream = new MemoryStream(new byte[SizeToReceive], true);
using (var networkStream = new NetworkStream(socket))
{
networkStream.CopyToExact(outputStream, buffer, SizeToReceive);
}
// Use the outputStream instance...
}
Important note
Please do not forget to call the Dispose() method of the instances of the Socket class (for both Sender and Receiver). The absence of the method call can be a root cause of the problems.
Got unknown issue with System.Net.Sockets in WP8.
The communication built on next schema - 4 first bytes - for package length, next 4 bytes for package number, and data. So [4][4][{any}] is a TCP package.
Reading of incoming data goes by next steps.
1. Read first 8 bytes.
2. Get package length from the first 4 bytes to determine size of incoming data.
3. Resize buffer to a proper size.
4. Read incoming data in buffer with offset 8 bytes.
I am sending a lot of packages to server.
Sometimes server's responses in incoming buffer are valid and can be read one by one.
But sometimes it seems the first 8 bytes from incoming data are skipped and with the steps 1-4 I am reading the first 8 bytes from the package's data.
Infinite loop for receiving
while (_channel.Opened)
{
Debug.WriteLine("Wait for incoming... ");
Stream responseStream = await _channel.Receive();
HandleIncomingData(responseStream);
}
Here code for socket:
public async Task<Stream> Receive()
{
byte[] buff = new byte[8];
ManualResetEventSlim mre = new ManualResetEventSlim();
var args = new SocketAsyncEventArgs();
args.SetBuffer(buff, 0, buff.Length);
EventHandler<SocketAsyncEventArgs> completed = (sender, eventArgs) => mre.Set();
EventHandler<SocketAsyncEventArgs> removeSubscription = (sender, eventArgs) => args.Completed -= completed;
args.Completed += completed;
args.Completed += removeSubscription;
_connectionSocket.ReceiveAsync(args);
mre.Wait();
args.Completed -= removeSubscription;
int len = BitConverter.ToInt32(buff, 0);
int num = BitConverter.ToInt32(buff, 4);
if (Math.Abs(_packageNumber - num) < 3)
{
Array.Resize(ref buff, len);
args.SetBuffer(buff, 8, buff.Length - 8);
args.Completed += completed;
args.Completed += removeSubscription;
mre.Reset();
_connectionSocket.ReceiveAsync(args);
mre.Wait();
}
Debug.WriteLine("Recv TCP package: {0}", args.Buffer.ToDebugString());
if (args.BytesTransferred == 0)
throw new SocketException();
byte[] result = new byte[buff.Length - 8];
Array.ConstrainedCopy(buff, 8, result, 0, result.Length);
MemoryStream stream = new MemoryStream(result, false);
return await Task.FromResult(stream);
}
It is 100% issue with crossthreading. Did the same in Console app.
If here
mre.Reset();
_connectionSocket.ReceiveAsync(args);
mre.Wait();
before mre.Wait() put Thread.Sleep(n), where n > 1 - everything works fine.
But this is very rude solution
Just to explain, I have a dev board that is, on command, shooting out 4 chars (Bytes). The terminal program (RealTerm) i'm using to debug this sees all 4 bytes. I've now moved on to writing the desktop software, and my program is only paying attention to 1 out of 4 bytes sent. TO clarify, i don't know which 1 of 4 bytes (first , last, middle two) but i can find out if its really necessary.
At first I thought the SerialPort.DataReceived event would fire for each byte that was received. This isn't true, I don't know what causes it to fire but its not the receiving of a singular Byte.
So I tried looping over SerialPort.BytesToRead, but this also only gets the first byte, even though it recognizes there are 3 bytes to read (why not 4??)
Its not essential for me to receive this data at the exact time it hits the port, but obviously I dot want to be loosing 3/4 of my data. However it wont always be 4 bytes, that's just what its doing now. I just want to get all bytes that are ready to be read.
Event Handler:
private void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
while (comPort.BytesToRead > 0)
{
RxString = comPort.ReadExisting();
RxByte = comPort.ReadByte();
byte[] myByte = new byte[6];
for (int i = 0; i < 6; i++)
{
myByte[i] = 0000000;
}
comPort.Read(myByte, 0, comPort.BytesToRead);
for (int i=0;i<6;i++)
{
if (myByte[i] != null)
{
thisBytes.Add(myByte[i]);
}
}
RxString = RxByte + "";
try
{
this.Invoke(new EventHandler(dealWithByte));
}
catch
{
}
}
}
private void dealWithByte(object sender, EventArgs e)
{
foreach (byte item in thisBytes)
{
RxByte = Convert.ToInt16(item);
string binary = Convert.ToString(RxByte, 2).PadLeft(8, '0');
//processTime(binary);
}
}
I am not a C# person but the code is pretty simple, pseudo code
numBytes As Int = SerialPort1.BytesToRead 'get # of bytes available
buf(numBytes - 1) As Byte 'allocate a buffer
br As Int = SerialPort1.Read(buf, 0, numBytes) 'read the bytes
If br <> numBytes {
Resize(buf, br) 'resize the buffer
}
at this point store the bytes into a list. This list can then be processed for messages.
I am trying to write data to serialport and then wait for the acknowledgement. After ack is received, I write the next set of data.
Please suggest a way of doing this. I tried the below code but before receiving the ack, the writing fires and completes execution.
When I run it in debug mode, it works fine, but when run without breakpoints, it doesnot run properly.
// some data for writing
byte[] data = "xxx";
byte[] data1 = "yyy";
byte[] data2 = "zzz";
// loop to write the above 5 times
int times = 1;
for (int i = 0; i < 20; i++)
{
if (Flag == true)
{
Flag = false;
if (times <= 5)
{
serialPort.Write(data, 0, data.Length);
serialPort.Write(data1, 0, data1.Length);
serialPort.Write(data2, 0, data2.Length);
times = times + 1;
}
}
else
{
MessageBox.Show("Some problem in ack...");
}
}
Flag = true;
private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//char[] buffer = new char[4];
//serialPort.Read(buffer, 0, 4);
Flag = true;
}
Are you trying to use Flag as the ack? The logic doesn't make sense. Don't you need to do something like
while (Flag == false)
; //wait for flag to become true after previous write
...write...
Flag = false;
You need a state machine pattern, or at least some way of storing state. By "State" I mean where you are in the process of reading/writing. State machines are a basic design pattern commonly used for communications (or any event driven programs), read up on them a bit:
http://www.codeproject.com/KB/architecture/statepatterncsharp.aspx
http://www.dofactory.com/Patterns/PatternState.aspx
http://en.wikipedia.org/wiki/State_pattern (I don't like the sample they chose here)
Somehow this has worked out,
byte[] data = "Your message to be sent on serial port";
serialPort.Write(data, 0, data.Length);
byte[] buffer = new byte[16];
int vintctr = 0;
while (vintctr < 16)
vintctr += serialPort.Read(buffer, 0, 16);
Debug this and you you can get the reply from the port.