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?
websssCEOAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

sarabandeCommented:

    1. Device connects to app:
    2. App creates a socket object for the particular device
    3. Device starts sending data
    4. Data is handled by OnRecievedData() delegate
    5. Device sends first data (login data) which is the IMEI of the device
    6. The IMEI data is assigned to the socket object

after point 2 your app should create a new thread which got the new socket (handle) and handles all communication to the new device connected.

the app (server) still handles the main socket where the devices cann connect to. normally i also would do that into a separate worker thread in order to keep your main thread (gui thread) responsive. if you do so you never would have any requests from devices which could be mixed-up with other input. to communicate between main thread and worker threads, you should have input queues for each thread and make all operations on those queues in a thread-safe way, i. e. you would lock the resource and do all reading, writing and deleting exclusively.

APP: 
- creates a new socket and binds it to the ip address
- creates a queue (main input queue) where it could receive requests and messages from threads
- creates a new thread (ACCEPT) and passes the socket and a handle to the queue to the thread
- on request event
  - retrieve request from main input queue and erase it from queue (pop request)
  - process the request and get result
  - push result into queue of the requester (client)
- on message event:
  - retrieve message from main input queue and erase it from queue
  - display/log message

DEV (device):
- connect to APP
- on connect
  - send request
  - wait for to receive result (best with timeout)
  - on success
    - disconnect 
  - on error (or timeout)
    - handle error
    - disconnect

ACCEPT:
- starts an infinite loop 
   - checks if user wants to terminate (if yes, break)
   - try to accept a new device (with timeout)
   - on accept
     - create a new thread (CLIENT)
     - pass the new socket and the handle to the main input queue to the thread
     - continue loop
   - on timeout
      - continue loop

CLIENT:
- create an input queue for results
- try to receive request from device (with timeout)
- on receive
  - handle request
    - pass request to main input queue
    - wait for result queue to get the result
    - on result
      - send result to device
      - delete result from queue
      - wait for disconnect
    - on timeout or on error 
      - send message to main input queue 
   - terminate

Open in new window


Sara
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
sarabandeCommented:
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
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
.NET Programming

From novice to tech pro — start learning today.