こんにちは私はC#でASCII文字列を受け取るプログラムを作成しました。文字列はXMLマークアップです。C#serial port時にはデータがありません
私からデータを受信するコンピュータが制御することはできません、それはすべての10分、私が収集して格納し、このデータを持っていますが、それ
。コンソールアプリについてのCOMポートにデータを送信し、応答を受け付けません常に動作しない私は時間のデータの約50%がパケットやバイトのように失われていると言うだろうし、XML文字列はXmlDocumentに読み込まれません
私はこれをより安定させるために約1週間これはC#で初めてのことですが、これを改善するためにいくつかの助けが必要です。
CODE
class SerialPortProgram : IDisposable
{
// Create the serial port with basic settings
private SerialPort port = new SerialPort("COM1",
115200, Parity.None, 8, StopBits.One);
string sBuffer = null;
string filePath1 = @"C:\Data\data1.xml";
string filePath2 = @"C:\Data\data2.xml";
[STAThread]
static void Main(string[] args)
{
// Instatiate this class
new SerialPortProgram();
}
private SerialPortProgram()
{
Console.WriteLine("Started Data Monitoring:");
//Attach a method to be called when there
//is data waiting in the port's buffer
port.ReadBufferSize = 20971520;
port.ReceivedBytesThreshold = 1;
port.DataReceived += new SerialDataReceivedEventHandler(Port_DataReceived);
//Begin communications
port.Open();
//Enter an application loop to keep this thread alive
Application.Run();
}
private void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//Show all the incoming data in the port's buffer
SerialPort sp = (SerialPort)sender;
sBuffer += sp.ReadExisting();
if (sBuffer.Length > 26000) // check the file size
{
if (sBuffer.Substring(sBuffer.Length - 6) == "</xml>") // check for end of file
{
Console.WriteLine("Found: Processing...");
//Thread.Sleep(1000);
ProcessXML();
sBuffer = null;
Console.WriteLine("Done!");
DateTime now = DateTime.Now;
Console.WriteLine(now);
Console.WriteLine("Monitoring...");
}
else
{
Console.WriteLine("Still Receiving Data: " + sBuffer.Length);
}
}
else
{
Console.WriteLine("Receiving Data: " + sBuffer.Length);
}
}
private void ProcessXML()
{
XmlDocument xmlDoc = new XmlDocument();
try
{
xmlDoc.LoadXml("<wrapper>" + sBuffer + "</wrapper>");
int index = 0;
XmlNodeList xnl = xmlDoc.SelectNodes("wrapper/xml");
foreach (XmlNode node in xnl)
{
// Console.WriteLine(index.ToString());
if (index == 0)// xml file 1
{
using (XmlReader r = new XmlNodeReader(node))
{
DataSet ds = new DataSet();
ds.ReadXml(r);
ds.WriteXml(filePath1);
Console.WriteLine("NEW Data1");
ds.Dispose();
var db = new Database();
db.SaveMetersToDatabase(ds);
}
}
else if (index == 1)// xml file 2
{
using (XmlReader r1 = new XmlNodeReader(node))
{
DataSet dst = new DataSet();
dst.ReadXml(r1);
dst.WriteXml(filePath2);
Console.WriteLine("NEW Data2");
dst.Dispose();
}
}
index++;
}
}
catch
{
Console.WriteLine("Error: in data");
try
{
string now = DateTime.Now.ToString("yyyyMMddHHmmss");
System.IO.File.WriteAllText(@"C:\Data\log" + now + ".xml", "<wrapper>" + sBuffer + "</wrapper>");
}
catch
{
Console.WriteLine("Failed to write to log");
}
}
}
protected virtual void Dispose(bool disposing)
{
if (disposing && port != null)
{
port.Dispose();
port = null;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
更新されたコード:
private void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//Show all the incoming data in the port's buffer
SerialPort sp = (SerialPort)sender;
sBuffer += sp.ReadExisting();
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
if (sBuffer.Length > 25000) // check the file size
{
if (sBuffer.Substring(sBuffer.Length - 6) == "</xml>") // check for end of file
{
Console.WriteLine("Found: Processing...");
Task.Run(() =>
{
ProcessXML();
sBuffer = null;
Console.WriteLine("Done!");
DateTime now = DateTime.Now;
Console.WriteLine(now);
Console.WriteLine("Monitoring...");
});
}
else
{
Console.WriteLine("Still Receiving Data: " + sBuffer.Length);
}
}
else
{
Console.WriteLine("Receiving Data: " + sBuffer.Length);
}
}).Start();
}
UPDATE
まだこの問題は、送信側コンピュータは時々すべてのデータを送信しない可能性があることができたか、パケットがあります私はシリアルポートBaseStream BeginReadを使用してこの新しいコードを試したすべてを試してみた
private SerialPortProgram()
{
Console.WriteLine("Started Data Monitoring:");
//Attach a method to be called when there
try
{
Port.BaudRate = 115200;
Port.DataBits = 8;
Port.Parity = Parity.None;
Port.StopBits = StopBits.One;
Port.Handshake = Handshake.None;
Port.DtrEnable = true;
Port.NewLine = Environment.NewLine;
Port.ReceivedBytesThreshold = 2048;
Port.Open();
byte[] buffer = new byte[35000];
Action StartRead = null;
StartRead =() => {
Port.BaseStream.BeginRead(buffer, 0, buffer.Length, async (IAsyncResult ar) =>
{
try
{
int actualLength = Port.BaseStream.EndRead(ar);
byte[] received = new byte[actualLength];
Buffer.BlockCopy(buffer, 0, received, 0, actualLength);
await Task.Run(() =>
{
sBuffer += Encoding.ASCII.GetString(received);
CheckBuffer();
});
}
catch (Exception exc)
{
Console.WriteLine(exc);
}
StartRead();
}, null);
};
StartRead();
}
catch (Exception ex)
{
Console.WriteLine("Error accessing port." + ex);
Port.Dispose();
Application.Exit();
}
//Enter an application loop to keep this thread alive
Application.Run();
}
private void CheckBuffer()
{
if (sBuffer != null && sBuffer.Length > 26000) // check the file size
{
if (sBuffer.Substring(sBuffer.Length - 6) == "</xml>") // check for end of file
{
new Thread(async() =>
{
Console.WriteLine("Found: Processing...");
await Task.Run(() => ProcessXML());
sBuffer = null;
Console.WriteLine("Done!");
DateTime now = DateTime.Now;
Console.WriteLine(now);
Console.WriteLine("Monitoring...");
}).Start();
}
else
{
Console.WriteLine("Still Receiving Data: " + sBuffer.Length);
}
}
else if (sBuffer != null && sBuffer.Length > 0)
{
Console.WriteLine("Receiving Data: " + sBuffer.Length);
}
}
何が眠っていますか?それはちょうどデータを失うことを求めている –
ええ、私はdidntそれはそれがファイルを保存していたのでそれに影響を与えると思ったが、それを再オープンする必要がなくなった必要がなくなった – Anthony
あなたのコールバックの時間の量を最小限に抑えたいあなたはデータを失うでしょう。 _circular buffer_または類似のテクニックを使用して、バッファを別の_thread_に移動することをお勧めします。 – MickyD