Link to home
Start Free TrialLog in
Avatar of websss
websssFlag for Kenya

asked on

Multi threading issue?

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 endpoint
tcp_listener.Bind(new IPEndPoint(IPAddress.Parse(“41.215.42.55”), 10005));

Open in new window


Set up a callback to be notified of connection requests:

tcp_listener.BeginAccept(new AsyncCallback(OnConnectRequest), tcp_listener);

Open in new window


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;

public void OnConnectRequest( IAsyncResult ar )
{
try
            {
                Socket listener = (Socket)ar.AsyncState;
                NewConnection(listener.EndAccept(ar));
                listener.BeginAccept(new AsyncCallback(OnConnectRequest), listener);
            }
            catch (SocketException e)
            {
                writeErrMsg(e.Message);
            }
}

Open in new window


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 buffer

public 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!" );
    }
}

Open in new window


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;

Open in new window


Device sends location data, this is assigned to the Connected Sockets’ device ID.
Instantiate an instance of the class that handles the data:
cdataHandler cdh = new cDataHandler();

Open in new window

Pass it the data received and IMEI of the device:
cdh.processMsg(Message, IMEI);

Open in new window


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?
ASKER CERTIFIED SOLUTION
Avatar of sarabande
sarabande
Flag of Luxembourg image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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