Please bear with me, this question is not going to be perfectly formed and/or may not have enough data for you to pin-point a cause. I am simply looking for ideas to continue solving this problem. Read as a horror story.
Problem Description
I have a C# program that interacts with an operator through button clicks, TCP/IP with a set of 4 barcode scanners, and some SQL. This is used in an somewhat-automated manufacturing setting. The barcode scanners come with a communications library to trigger barcode reading, as well as aggregate the data from 4 (or more) scanners into a single data stream to a client (my c# program). Each scanner provides the scanner ID as well as the scanned data, for example: 001:111111;004:444444;003:333333;002:222222.... 001, 004, 003 being the scanner's ID, while 111111, 222222, 333333, 444444 being the barcode data at those associated scanners.
I must apologize, you must be wondering why all these details but they come in play.
We run this program about 1000 times a day, mostly successfully. But at about 0.2% of the times, something unexpected happens.
Normal program flow (99.8%):
SQL Connection Open
User button press
Scanner trigger
Scanner returns data
SQL Operations (New code Registered)
Abnormal program flow (0.2%)
SQL Connection Open
User button press
Scanner trigger
Scanner returns incorrect data
SQL Operations
**Program rewinds back to start
SQL Connection Open
User button press bypassed
Scanner trigger bypassed
Scanner returns GOOD data
SQL Operations
Here is a captured sequence of events in log with bold comments:
SQL Connection Open.
K-----e Scanner LF Connect success? True
K-----e Scanner RF Connect success? True
K-----e Scanner LB Connect success? True
K-----e Scanner RB Connect success? True
New code Registered: 785889<=>819345 wrong data
New code Registered: 917890<=>481899 wrong data
New code Registered: 249447<=>999731 wrong data
New code Registered: 967082<=>386511 wrong data
New code Registered: 794079<=>772860 wrong data
New code Registered: 349467<=>421658 wrong data
New code Registered: 810132<=>525941 wrong data
New code Registered: 879309<=>105578 wrong data
SQL Connection Open. Rewind back to start of cycle, all without any user interaction
K-----e Scanner LF Connect success? True
K-----e Scanner RF Connect success? True
K-----e Scanner LB Connect success? True
K-----e Scanner RB Connect success? True
785889 is not unique. Data is good now, DB ops correctly since all scanned data was already inserted into DB
Already Exist 785889
819345 is not unique.
Already Exist 819345
917890 is not unique.
Already Exist 917890
525941 is not unique.
Already Exist 525941
249447 is not unique.
Already Exist 249447
105578 is not unique.
Already Exist 105578
967082 is not unique.
Already Exist 967082
481899 is not unique.
Already Exist 481899
794079 is not unique.
Already Exist 794079
421658 is not unique.
Already Exist 421658
349467 is not unique.
Already Exist 349467
772860 is not unique.
Already Exist 772860
810132 is not unique.
Already Exist 810132
386511 is not unique.
Already Exist 386511
879309 is not unique.
Already Exist 879309
999731 is not unique.
Already Exist 999731
Known Issues
After debugging (which is difficult due to the 0.2% occurrence), the scanner communications library is implicated for the wrong (scrambled) data 001:222222;004:111111;003:222222;002:333333, etc. I am concerned that the data is bad, but I am much more concerned about the program rewind.
Question
What mechanism(s) or conditions could result in repeated code execution, triggered by an external library in C# windows form? How can I detect and trap such events?
Conclusion
My apologies for the long and incomplete description of this problem, I have included the information that I could gather in this question. It is certainly beyond normal to see this happen, and repeatedly. I hope to gather some information from your replies to help me further diagnose or fix this problem.
I have discussed this problem with my local scanner rep, but software libraries are provided as-is. These scanners are $10K each, but this is now a problem that I have to solve.
Here's one idea: The barcode scans are probably event-driven. If the events occur too closely to each other there's no guarantee that one will complete its query before the next event triggers a different query. There's an easy way to make the thread wait for an action to complete using a basic sychronization object in System.Threading.SemaphoreSlim.
public void DoSomeSqlOperations()
{
try
{
_ssEnforceSingleOperation.Wait();
using(var cnx = new SQLite.SQLiteConnection(ConnectionString))
{
// Perform the query
}
}
catch (Exception ex)
{
Debug.Assert(false, ex.Message);
}
finally
{
// Ensure the semaphore releases even if an error occurs.
_ssEnforceSingleOperation.Release();
}
}
SemaphoreSlim _ssEnforceSingleOperation = new SemaphoreSlim(1, 1);
If an operation is already in progress, the new one won't begin until the first one completes and releases the semaphore. My suggestion would be to protect your critical sections in this manner and see it it helps.
Related
I'm using the .NET Connector to access a MySQL database from my C# program. All my queries are done with MySqlCommand.BeginExecuteReader, with the IAsyncResults held in a list so I can check them periodically and invoke appropriate callbacks whenever they finish, fetching the data via MySqlCommand.EndExecuteReader. I am careful never to hold one of these readers open while attempting to read results from something else.
This mostly works fine. But I find that if I start two queries at the same time, then I get the dreaded MySqlException: There is already an open DataReader associated with this Connection which must be closed first exception in EndExecuteReader. And this is happening the first time I invoke EndExecuteReader. So the error message is full of baloney; there is no other open DataReader at that point, unless the connector has somehow opened one behind the scenes without me calling EndExecuteReader. So what's going on?
Here's my update loop, including copious logging:
for (int i=queries.Count-1; i>=0; i--) {
Debug.Log("Checking query: " + queries[i].command.CommandText);
if (!queries[i].operation.IsCompleted) continue;
var q = queries[i];
queries.RemoveAt(i);
Debug.Log("Finished, opening Reader for " + q.command.CommandText);
using (var reader = q.command.EndExecuteReader(q.operation)) {
try {
q.callback(reader, null);
} catch (System.Exception ex) {
Logging.LogError("Exception while processing: " + q.command.CommandText);
Logging.LogError(ex.ToString());
q.callback(null, ex.ToString());
}
}
Debug.Log("And done with callback for: " + q.command.CommandText);
}
And here's the log:
As you can see, I start both queries in rapid succession. (This is the first thing my program does after opening the DB connection, just to pin down what's happening.) Then the first one I check says it's done, so I call EndExecuteReader on it, and boom -- already it claims there's another open one. This happens immediately, before it even gets to my callback method. How can that be?
Is it not valid to have two open queries at once, even if I only call EndExecuteReader on one at a time?
When you run two queries concurrently, you must have two Connection objects. Why? Each Connection can only handle one query at a time. It looks like your code got into some kind of race condition where some of your concurrent queries worked and then a pair of them collided and failed.
At any rate your system will be more resilient in production if you can keep your startup sequences simple. If I were you I'd run one query after another rather than trying to run them all at once. (Obvs if that causes real performance problems you'll have to run them concurrently. But keep it simple until you need it to be complex.)
It's pretty straightforward to listen for BLE advertisements and get the BluetoothAddress, signal strength etc from the advert. This page says
Once you have the address, you can call BluetoothLEDevice.FromBluetoothAddressAsync to get a reference to the device.
so I did and this gave me a BluetoothLEDevice object with a Name property. Unfortunately the name is frequently - but not always - an empty string.
When I interactively scan for Bluetooth devices, Windows shows me a list of names for devices it can see (excluding already paired devices). It does this very quickly and it shows a number of devices that don't ever show up in the names accumulated from advertising.
Is there a reliable strategy for quickly obtaining the name normally shown when computers and phones list unpaired devices?
I tried the suggestion from Emil, and while this simplifies my code by eliminating the need to obtain a BluetoothLEDevice object, the fundamental problem remains: advertisements cannot be relied upon to supply a name. They don't even contain meaningful manufacturer data.
The code currently looks like this
BluetoothLEAdvertisementWatcher watcher = new BluetoothLEAdvertisementWatcher();
...
watcher.Received += OnAdvertisementReceived;
watcher.Start();
...
private void BleAdvertHandlerAsync(BluetoothLEAdvertisementReceivedEventArgs args)
{
var localName = args.Advertisement.LocalName;
...
}
Fishing the local name into a variable sidesteps the fact that resolving the value entails a COM call which is not allowed in a breakpoint expression.
Playing with the switches on my mouse and keyboard, which can be paired with three different hosts and switched between them, I notice that when I tell them to connect to another host I immediately get advertisements containing names. If the host isn't present there is a steady stream of them that ceases when I switch back to my computer and a session is established.
This suggests that advertisements are not the way Windows populates its list of unpaired hosts.
If you use the advertisement watcher you can check the BluetoothLEAdvertisement.LocalName property.
For your second question, maybe your phone is discovered through Bluetooth Classic?
I am developing a C# WinForms Windows application that runs from the tray. I need to provide some reasonable level of error handling and instruction to the user. In order to test if I am able to open a serial port for communication, I wish to have a way to test if it is already open or if it is unopenable for whatever reason.
I came up with this:
if (SerialPort.GetPortNames().Select((n) =>
n.ToUpperInvariant()).Contains(mycomportname))
{
// Port found, check to see if we can use it by test-opening
using (var sp = new SerialPort(mycomportname))
{
// Check to see if we can open this port
try
{
if (sp.IsOpen) throw new Exception("Serial port is already open");
sp.Open();
sp.Close();
}
catch (Exception ex)
{
throw new Exception("Serial port is in use");
}
}
}
else
{
// ...
}
commManager.PortName = mycomportname;
if (commManager.OpenPort())
{
// .. always returns false because causes UnauthorizedAccessException on open
}
For some reason the serial port does not seem to be fully released by the 'using' statement. The UnauthorizedAccessException does not occur when I delete the using statement and the statements inside it. How do I write robust error-tolerant serial port opening code?
The MSDN article for SerialPort warns about this explicitly, albeit vaguely. SerialPort uses a worker thread to generate events like DataReceived and ErrorReceived. That thread gets started when you call Open() but it needs time to exit again after you call Close() or Dispose(). The physical port is in use until that happens. Exactly how long that takes is unpredictable. Usually within a millisecond but the worst-case is seconds when the machine is heavily loaded. Your code only waits for a nanosecond so you'll always get an exception.
The approach otherwise just doesn't make sense. Once you opened the port and got no exception then just keep it open. No point in closing it again and reopening it. Which is the simple solution.
And never do this kind of port scanning when GetPortNames() returns more than one port. The odds that the first one will open are very high, the odds that it is the right one are low. Murphy ensures that fifty-fifty odds turn into 1%. You always need to provide a config file so the user can pick the correct one. Only consider doing the port scanning when you populate a combobox with choices in a config helper window. Only skimp on this if you are in control over the machine configuration, that's pretty rare.
I have an assignment where I need to load some data like user (pouzivatel) and some int(stav odberu) through link modem with the serial port and store it in my local database. I know how to load data, send data over the serial port, but I need to make it happen in a structure on the image.
First I dial the telephone number of the device with AT command, btw this is working, but I do not know now how to stop and wait for SOH+adresa objektu (SOH+some string about address). Then send data about confirmation (ACK) and wait for new data to come.
The wait sequence is my biggest problem. How do I stop and wait for data being received.
Using the component and utilizing its DataReceived event as suggested in the comments would probably solve your problem easy and effectively. But you may have been looking for something more low-level to do it yourself.
If you want/need to do it in-line without any fancy event based system that would assume you are already in some message queue based environment like WinForms, you could do something like this.
while (true)
{
// check for new data
...
// if you got some, respond to it
...
if (someConditionThatTellsYouYouAreDoneOrSupposedToTerminate) break;
System.Threading.Thread.Sleep(50);
}
Background
Hi.
I write a program that analyzes the packets for specific words contained therein. I need to analyze outgoing email, jabber, ICQ. If the words are found, the packet is blocked.I did it, but I have a problem with the files and sending email through the web.
Problems
Simple code:
while (Ndisapi.ReadPacket(hNdisapi, ref Request))
{
// some work
switch (protocol)
{
//....
case "HTTP":
// parse packet(byte[])
HTTP.HttpField field = HTTP.ParseHttp(ret);
if (field != null && field.Method == HTTP.HttpMethod.POST)
{
// analyze packet and drop if needed
DoWork();
}
}
The problem is the following. For example, I attach to email the file of 500 KB. The file will be split approximately in 340 packets. In the code above, DoWork() only for first packet will be executed.
Ok, then I need to restore session completely and pass whole session to DoWork(). I did it. But I can't wait while session is finished, because other packet( http, arp, all packets) will be suspended (And after a couple of minutes the Internet is disconnected).
Therefore, the first question:
How to solve this problem (may be advice for design program)?
Now the email, suppose this code:
switch (protocol)
{
//....
case "HTTP":
// parse packet(byte[])
var httpMimeMessage = Mime.Parse(ret);
// analyze packet and drop if needed
DoSomeWork();
break;
}
For example, we are looking for word "Finance". Then, if we open any website and there will be a word finance then packet is blocked.
Second question: How do I determine that this is the e-mail?
Thanks and sorry for my English.
To be able to analyze more than one packet/stream at the same time, you'll need to refactor your solution to use threading or some other form of multitasking and since your task appears to be both compute and io-intensive, you'll probably want to take a hard look at how to leverage event-handling at the operating system level (select, epoll, or the equivalent for your target platform).
And to answer your second question regarding email, you'll need to be able to identify and track the tcp session used to deliver email messages from client to server, assuming the session hasn't been encrypted.
As I'm sure you already know, the problem you're trying to solve is a very complicated one, requiring very specialized skills like realtime programming, deep knowledge of networking protocols, etc.
Of course, there are several "deep packet inspection" solutions out there already that do all of this for you, (typically used by public companies to fulfill regulatory requirements like Sarbanes-Oxley), but they are quite expensive.