I am working on a gps tracking Windows application that uses Asychronous socket communication to talk to the tracking device(s).
I'm having a problem where data from one unit is contaminating data with another unit
The IMEI in the unique identifier
However the IMEI only comes in on the handshake, after this, the IMEI isn't sent, so i store the IMEI and REMOTE ENDPOINT in an object, and use the REMOTE ENDPOINT (which is available on each subsequent message) to look up the IMEI number
The issue seems to be related to the app being multi threaded.
Here is the process:
So I basically create a listener socket:
tcp_listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);Bind to an endpointtcp_listener.Bind(new IPEndPoint(IPAddress.Parse(“41.215.42.55”), 10005));
so upto this point, we are ready to accept connection requests from devices. When a device tries to connect, OnConnectRequest() event handler is fired
Socket client;
To receive data asynchronously, it is necessary to setup an AsyncCallback to handle events triggered by the Socket such as new data and loss of connection. This is done using the following method
private byte [] m_byBuff = new byte[1024]; // Received data bufferpublic void SetupReceiveCallback( Socket sock ){ try { AsyncCallback recieveData = new AsyncCallback( OnReceivedData ); sock.BeginReceive( m_byBuff, 0, m_byBuff.Length, SocketFlags.None, recieveData, sock ); } catch( Exception ex ) { MessageBox.Show( this, ex.Message, "Setup Recieve Callback failed!" ); }}
The SetupReceiveCallback method starts a BeginReceive using a delegate pointing to the OnReceiveData() method that follows. It also passes a buffer for the receive data to be inserted into.
Now herein lies the problem. The device connects and sends a login message which has the device ID (IMEI), this happens only once during the life of the socket. I normally create a field on a custom socket object and store the device ID. Any subsequent data that comes in on this particular Socket object gets tied to the initial device ID.
Each device that connects has it’s own socket object created and this stores the information about the connection including the device ID.
I have a separate class that processes the data unto which we pass the Device ID of the connected object. So when data comes in on OnReceiveData(), I just pass that data to the particular socket object that was created when the particular device connected.
However, I have had issues where the Device ID of a particular connected device get’s passed to a totally different Socket object. As a result, data from device A gets assigned to device B despite each having a separate Socket object ties to their particular connections. Here’s the sequence of events:
Device connects to app:
App creates a socket object for the particular device
Device starts sending data
Data is handled by OnRecievedData() delegate
Device sends first data (login data) which is the IMEI of the device
The IMEI data is assigned to the socket object
if (protocol_check[3] == "01") { string[] arr_data = new string[aryRet.Length]; for (int i = 0; i < aryRet.Length; i++) arr_data[i] = int.Parse(aryRet[i].ToString()).ToString("X").PadLeft(2, '0'); StringBuilder sb = new StringBuilder(); sb.Append(arr_data[0] + arr_data[1] + "05"); sb.Append(arr_data[3]); if (protocol_check[2]=="11") sb.Append(arr_data[16] + arr_data[17]); else sb.Append(arr_data[12] + arr_data[13]); byte[] dataPacket = hexStringToByteArray(sb.ToString()); var crc16 = GetCrc16(dataPacket, 2, 4); string error_check = string.Format("{0:X}", (int)crc16); sb.Append(error_check + "0D0A" //get the IMEI for (int i = 4; i < 12; i++) nUnitID += arr_data[i]; nUnitID = nUnitID.Substring(1, 15); //assign to active socket client.DEVICE_ID = nUnitID;
The IMEI that is passed to cdh.processMsg is fine and corresponds to the sending device. However when you examine the IMEI inside cdh.processMsg, it’s totally different from what was passed in through on OnRecievedData().
Question is, why would the data on the calling Async method be different from the one on the method on the instance of the data handling class? Is this a threading issue. Despite creating function to create thread safety for the method calls on the received data, the issue still persists. What would be the best way to handle received data in such an instance so it doesn’t cross contaminate?
There was no response to the sole comment. But as this was a complete multi-threading programming design, it might have helped nevertheless, or might help others in future.
Sara