I am working with serial ports c#, CF 2.0
Can this function be trusted to return 0 when there is nothing to read?
while (_sp.BytesToRead > 0)
{
char[] buffer = new char[255];
int bytes_read = _sp.Read(buffer, 0, buffer.Length);
for (int i = 0; i < bytes_read; i++)
{
value += buffer[i];
}
}
ProcessValue(value);
what I want to do it read the data until there are no more bytes to read.
_sp is an instance of SerialPort class
Yes. However, it may throw an exception - so be sure to handle that. See MSDN.
Related
I want to communicate with a DSP using RS232, so I use System.IO.SerialPort to achieve this. Everything goes well except the reading performance.
Every 200ms, the port can received a package of 144 bytes. But in the tests, the applications almost skip every other package. I try to print the system time in the console. It amaze me that the code below (when length = 140) take me over 200ms. It let the application can not handle the data in time.
Does anything wrong I do?
Port Property:
BaudRate = 9600
Parity = None
StopBits = One
private byte[] ReadBytesInSpicifiedLength(int length)
{
byte[] des = new byte[length];
for (int i = 0; i < length; i++)
{
des[i] = (byte)serialPort.ReadByte();
}
return des;
}
You're doing a lot of individual I/O calls, which means a lot of kernel transitions. Those are expensive. Not being able to reach 720 bytes per second is surprising, but you can make the data handling an order of magnitude faster by doing block reads:
private byte[] ReadBytesWithSpecifiedLength(int length)
{
byte[] des = new byte[length];
serialPort.BaseStream.Read(des, 0, des.Length);
return des;
}
If you have timeouts enabled, you could get partial reads. Then you need to do something like:
private byte[] ReadBytesWithSpecifiedLength(int length)
{
byte[] des = new byte[length];
int recd = 0;
do {
int partial = serialPort.BaseStream.Read(des, recd, length - recd);
if (partial == 0) throw new IOException("Transfer Interrupted");
recd += partial;
} while (recd < length);
return des;
}
The nice thing about BaseStream is that it also has async support (via ReadAsync). That's what new C# code should be using.
I'm trying to send a long string from a python server to a C# client. The string is 230400 bytes long. I'm both sending and receiving in chunks of 64 bytes. Server code:
import socket
def initialize():
global s
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('', 1719))
s.listen()
initialize()
while(1):
sock, addr = s.accept()
msgstr = generate_msg_string() # irrelevant
msglen = len(msgstr)
totalsent = 0
while totalsent < msglen:
sent = sock.send(msgstr[totalsent:totalsent+64])
totalsent = totasent + sent
sock.close()
Client code:
TcpClient tcpClient = new TcpClient();
tcpClient.Connect(ip, 1719);
byte[] ba = new byte[230400];
byte[] buffer = new byte[64];
tcpClient.ReceiveBufferSize = 64
int i=0;
while(i != 230400)
{
stream.Read(buffer, 0, 64);
buffer.CopyTo(ba, i);
i += 64;
}
tcpClient.Close();
I've checked a few connections in a row - the first 1523 bytes are correct and all the rest are gibberish - at least seemingly random.
Any idea what might be the cause?
while(i != 230400)
{
stream.Read(buffer, 0, 64);
buffer.CopyTo(ba, i);
i += 64;
}
The fundamental error here is assuming that Read read 64 bytes. It can read any of:
0 if the socket gets closed for any reason
64 bytes if that happens to be available and it chooses to
1-63 bytes, just for fun
You are not guaranteed anything other than "non-positive if the stream is closed, else at least 1 byte and no more than 64 bytes"
You must must must read the return value of Read and only process that much of the buffer. This remains the case if you switch to Socket.Receive, by the way.
Also - why don't you just fill ba in the first place, increment in the offset and decrementing the count each time?
int count = 230400, offset = 0, read;
byte[] ba = new byte[count];
while(count > 0 && (read=stream.Read(ba, offset, count)) > 0)
{
offset += read;
count -= read;
}
if(read!=0) throw new EndOfStreamException();
It seems that I hurried with the question.
Changing TcpClient to Socket fixed the problem. The approach remained the same.
I've written an application which listens to a port and receives some packets,according to my customized protocol, the packets are either 49 byte to 1500 byte, which i can tell from data length in the packet. the way i should interpret and deal with data in 49 byte packets and bigger packets are different.
The problem is that when i receive packets less than 1374 byte everything is ok, but when the packet length gets more, i receive the following exception and i also lose 4 last bytes of my data(i've tested with a 1384byte packet and i lost the last 4 bytes)
Exception which is raised:
Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: startIndex
each 49 byte packet has 35 byte of data, and the data length of bigger packets are non-deterministic(because of compression).
i found out sometimes the last 4 bytes are in a seperate "bytes" and "result" variables,meaning they are being treated like new packets and are not being attached to the packet they belong to.
here's the code for receiving data:
TcpClient Client = obj as TcpClient;
EndPoint ep = Client.Client.RemoteEndPoint;
List<Byte> result = new List<byte>();
result.Capacity = 2000;
try
{
NetworkStream stream = Client.GetStream();
int i = 49;
while ((i = stream.Read(bytes, 0,49)) != 0)
{
for (int id = 0; id < i; id++)
{
result.Add(bytes[id]);
}
//reading data length to determine packet length
byte[] tmp = new byte[2];
tmp = BitConverter.GetBytes(BitConverter.ToUInt16(result.ToArray(), 9));
if (BitConverter.IsLittleEndian)
{
Array.Reverse(tmp);
}
Int16 l = BitConverter.ToInt16(tmp, 0);
if (l>35)
{
stream.Read(bytes, result.Count, l - 35);
for (int id = 49; id <((l-35)+49); id++)
{
result.Add(bytes[id]);
}
if (this.TCPDataReceivedHandler != null)
{
this.TCPDataReceivedHandler(ep, result.Count, result.ToArray());
result.Clear();
Array.Clear(bytes, 0, 2000);
result.Capacity = 2000;
}
}
else
{
if (this.TCPDataReceivedHandler != null)
{
this.TCPDataReceivedHandler(ep, result.Count, result.ToArray());
result.Clear();
Array.Clear(bytes, 0, 2000);
result.Capacity = 2000;
}
}
}
System.Diagnostics.Debug.WriteLine("client Close");
Client.Close();
}
catch (System.Exception ex)
{
throw ex;
}
finally
{
Client.Close();
this.clients.Remove(Client);
}
According to Greg Suggestion and my researches,i also tried using following method:
NetworkStream stream = Client.GetStream();
int bytesread = 0, OffsetTemp = 0;
while (stream.CanRead)
{
OffsetTemp = 0;
bytesread += stream.Read(bytess, OffsetTemp, 11);
OffsetTemp = OffsetTemp + 11;
byte[] tmp = new byte[2];
tmp = BitConverter.GetBytes(BitConverter.ToUInt16(bytess.ToArray(), 9));
if (BitConverter.IsLittleEndian)
{
Array.Reverse(tmp);
}
Int16 l = BitConverter.ToInt16(tmp, 0);
bytesread += stream.Read(bytess, OffsetTemp++, 11 + l + 3);
for (int id = 0; id < l + 14; id++)
{
result.Add(bytess[id]);
}
if (this.TCPDataReceivedHandler != null)
{
this.TCPDataReceivedHandler(ep, result.Count, result.ToArray());
result.Clear();
Array.Clear(bytess, 0, 2000);
}
}
When using TCP, you must keep in mind that the size of the data blocks you put in is not guaranteed to be the same size of data blocks you get out on the receiving side. TCP is a stream protocol, so it guarantees that the same bytes get to the other side in the same order as they were sent (if not, the socket connection will be reset). TCP does not maintain any kind of block boundaries between calls to send(), and blocks may be arbitrarily split or coalesced depending on network conditions.
Your receiver must be prepared to handle receiving any amount of data from the calls to stream.Read(), but your code does not appear to do this. For example, correctly written receiver code should continue to work correctly even if stream.Read() receives only one byte at a time.
I want to communicate between my PC and some controller boards.
The expectation is that the PC will send an identifier of the board on RS-485 and then it should receive the answer from the board.
When I try to receive the response, I receive the wrong data.
Here is my code:
public void set()
{
SerialPort sp = new SerialPort("COM1");
sp.Open();
if (sp.IsOpen)
{
byte[] id = new byte[]{0,0,0,0,0,0,0,0,0,0};
byte[] rec = new byte[540];
while (!end)
{
sp.Write(id,0,id.Length);
sp.Read(rec,0,rec.Length);
//do some with rec
//WORKING
//do soem with rec
}
}
sp.Close();
}
It works if I am using RS-232, but not when I am using RS-485.
UPDATE :
It is RS-485 2 wire.(http://en.wikipedia.org/wiki/RS-485)
I found the problem.
sp.Read(rec,0,rec.Length);
Read is a non-blocking method so it reads the buffer but does not wait for all of the bytes. So you need to use the return value of this function which returns an integer with a number of bytes that it could read.
I am using this:
int read = 0;
int shouldRead = readData1.Length;
int len;
while (read < shouldRead )
{
len = serialport.Read(buffer, 0, readData1.Length);
if (len == 0)
continue;
Array.Copy(buffer, 0, readData1, read, len);
read += len;
Thread.Sleep(20);
}
I have to trnasfer large file, at this moment I use TcpClient and NetworkStream class to do that, but it isn't enought. When I use NetworkStream.Write and Read it lose bytes I don't know how can I ensure that TCP will stop reading when all bytes will be ok.
Then I found Socket Class, and now my question, "Socket will be perfectly sure about all bytes before it end read?"
How I recive file:
byte[] VideoFrom = new byte[FizeSizeSendedBefore];
byte[] PartData = new byte[clientSocket.ReceiveBufferSize];
int PartNumbers = (VideoSize / clientSocket.ReceiveBufferSize) + 1;
int lastPackageSize = VideoSize - ((PartNumbers - 1) * clientSocket.ReceiveBufferSize);
int i;
int bytesToRead = 0;
int ActualSize = 0;
for (i = 0; i < PartNumbers; i++)
{
if (i < PartNumbers - 1)
{
bytesToRead = clientSocket.ReceiveBufferSize;
}
else
{
bytesToRead = lastPackageSize;
}
ActualSize += bytesToRead;
PartData = new byte[bytesToRead];
System.Threading.Thread.Sleep(2);
networkStream.Read(PartData, 0, bytesToRead);
Buffer.BlockCopy(PartData, 0, VideoFrom, i * clientSocket.ReceiveBufferSize, bytesToRead);
}
if (!Directory.Exists("./temp/anwsers/" + AnwserXML.Attribute("number").Value)) { Directory.CreateDirectory("./temp/anwsers/" + AnwserXML.Attribute("number").Value); }
File.WriteAllBytes("./temp/anwsers/" + AnwserXML.Attribute("number").Value + "/" + AnwserXML.Attribute("client").Value + ".mov", VideoFrom);
}
How I send file
int PartNumber = (FizeSizeSendedBefore/ clientSocket.ReceiveBufferSize) + 1;
int lastPackageSize = FileSize - ((PartNumber - 1) * clientSocket.ReceiveBufferSize);
int i;
for (i = 0; i < PartNumber; i++)
{
if (i < PartNumber - 1)
{
while (!serverStream.CanRead) { }
serverStream.Write(outStream, i * clientSocket.ReceiveBufferSize, clientSocket.ReceiveBufferSize);
}
else
{
while (!serverStream.CanRead) { }
serverStream.Write(outStream, i * clientSocket.ReceiveBufferSize, lastPackageSize);
}
}
This is the problem:
networkStream.Read(PartData, 0, bytesToRead);
Never ignore the return value of Read. Never assume that a single call to read will read all of the data. You need to loop round, reading until it's all "in". The number of calls to Read which are required to read all data is pretty much unrelated to the number of calls to Write. TCP is a stream protocol - treat it that way.
It's not clear whether you know exactly how much data you're expecting to read - do you? Will the server close the connection at the end? If so, and if you're using .NET 4, then you can get rid of a huge amount of this code:
using (Stream output = File.Create(filename))
{
networkStream.CopyTo(output);
}
TCP will receive a chunk of data at a time - it will not lose data, but if you do not cater for the fact that data will be spilt into packets and will arrive one after the other and (often) not as one big "file", then you may not be listening for the rest of the data - this will seem like it is missing data, but really it is the code ignoring the rest after the first packet is received. Just because you sedn it in one lumnp, this does not mean it will arrive in one lump.
There are many examples of TCP server/client apps (and chat apps) out there in the wonderful world of google for you to compare notes on - alternatively post your code and we can then see where the error is.
How large is your file? Maybe it will be enough WebClient.DownloadDataAsync(...)?
UPDATED
If file is about 100Mb use simple WebClient :)
WebClient wc = new WebClient();
wc.DownloadDataCompleted += new DownloadDataCompletedEventHandler(OnDownloadDataCompleted);
wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(OnDownloadProgressChanged);
wc.DownloadDataAsync(new Uri("http://www.xxxx.com/t.tar.gz"));