Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. TCP server handle Clients, std::map or array?

TCP server handle Clients, std::map or array?

Scheduled Pinned Locked Moved C / C++ / MFC
questionsysadmindata-structures
7 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • B Offline
    B Offline
    bestbear
    wrote on last edited by
    #1

    struct CLIENT_DATA
    {
    int m_nOnlineTime;
    int m_nCredits;
    };

    for a tcp server which would handle at most 10240 clients. I want to manage all the clients.there are two solutions 1: use a std:map, and a mutex over all map operation 2: use a C array. and assign an ID(0-10239) for each client if connected,If disconnected,the Id would be recycled. if I use an array,mutex would only be necessary over the ID operations.such as assign an Id to a client when connected,recycle an Id when a client is disconnected. in fact,they are not different if I only have to handle connect or disconnect. but if I want to change the CLIENT_DATA for each client. for the first solution:I have to lock the whole map; for the second, I could maintain a mutex in each CLIENT_DATA. my question is, solution 1 is much more easy to code.solution 2 seems much more efficient. which one do you prefer? Thank you.

    A J 2 Replies Last reply
    0
    • B bestbear

      struct CLIENT_DATA
      {
      int m_nOnlineTime;
      int m_nCredits;
      };

      for a tcp server which would handle at most 10240 clients. I want to manage all the clients.there are two solutions 1: use a std:map, and a mutex over all map operation 2: use a C array. and assign an ID(0-10239) for each client if connected,If disconnected,the Id would be recycled. if I use an array,mutex would only be necessary over the ID operations.such as assign an Id to a client when connected,recycle an Id when a client is disconnected. in fact,they are not different if I only have to handle connect or disconnect. but if I want to change the CLIENT_DATA for each client. for the first solution:I have to lock the whole map; for the second, I could maintain a mutex in each CLIENT_DATA. my question is, solution 1 is much more easy to code.solution 2 seems much more efficient. which one do you prefer? Thank you.

      A Offline
      A Offline
      Afzaal Ahmad Zeeshan
      wrote on last edited by
      #2

      Quote:

      use a std:map, and a mutex over all map operation

      Only understandable way to do this. But has some constraints. My assumptions won't consider that using a mutex is necessary unless your application allows asynchronous processing + write access for connected devices. If writing process is maintained by your server program, then you know how to do that — Hint: create a condition inside function and don't make it visible in threads, abstract the implementation.

      Quote:

      use a C array. and assign an ID(0-10239) for each client if connected,If disconnected,the Id would be recycled.

      How about you don't use this. Suppose if there are only 10 clients connected, C array will still allocate all of the areas in RAM. Totally not worth it, and as you said — Id would be recycled —, how? What is your algorithm for that? There are many parts missing in your post, such as, what data will they access, are they going to write data too, to same file or not — mutex and thread-safety makes sense if something is happening on same time at different threads, if not then don't worry about this.

      The shit I complain about It's like there ain't a cloud in the sky and it's raining out - Eminem ~! Firewall !~

      B 1 Reply Last reply
      0
      • A Afzaal Ahmad Zeeshan

        Quote:

        use a std:map, and a mutex over all map operation

        Only understandable way to do this. But has some constraints. My assumptions won't consider that using a mutex is necessary unless your application allows asynchronous processing + write access for connected devices. If writing process is maintained by your server program, then you know how to do that — Hint: create a condition inside function and don't make it visible in threads, abstract the implementation.

        Quote:

        use a C array. and assign an ID(0-10239) for each client if connected,If disconnected,the Id would be recycled.

        How about you don't use this. Suppose if there are only 10 clients connected, C array will still allocate all of the areas in RAM. Totally not worth it, and as you said — Id would be recycled —, how? What is your algorithm for that? There are many parts missing in your post, such as, what data will they access, are they going to write data too, to same file or not — mutex and thread-safety makes sense if something is happening on same time at different threads, if not then don't worry about this.

        The shit I complain about It's like there ain't a cloud in the sky and it's raining out - Eminem ~! Firewall !~

        B Offline
        B Offline
        bestbear
        wrote on last edited by
        #3

        Ok,let me explain it in details 1 I have to maintain a collection for all the clients data,such as

        struct CLIENT_DATA
        {
        std::string m_strIp;
        int m_nOnlineTime;
        int m_nCredits;
        };

        2 the client data update(by a timer for example) and the socket are in different thread so If I use a map

        bool Connect(std::string strIp)
        {
        boost::lock_guard lock(m_lock);

        CLIENT_DATA* pData = new CLIENT_DATA;
        pData->m_nOnlineTime = 0;
        pData->m_strIp = strIp;
        m_mapClients.push_back(strIp,pData);

        return true;
        }

        void Disconnect(std::string strIp);
        {
        boost::lock_guard lock(m_lock);

            std::map::iterator iter = m\_mapClients.find(strIp);
        if(iter != m\_mapClients.end())
        	return;
        
        CLIENT\_DATA\* pClientData = m\_mapClients\[strIp\];
        if(pClientData != NULL)
            {
               delete pClientData;
               pClientData = NULL;
            }
            m\_mapClients.erase(iter);
        

        }

        bool UpdateOnlineTime(std::string strIp)
        {
        boost::lock_guard lock(m_lock);

            std::map::iterator iter = m\_mapClients.find(strIp);
        if(iter != m\_mapClients.end())
        	return false;
        
        CLIENT\_DATA\* pClientData = m\_mapClients\[strIp\];
        if(pClientData == NULL)
                   return false;
        pClientData->m\_nOnlineTime += 10;
        
        return true;
        

        }

        I have to lock the map use the same mutex in connect,disconnect,updateonlinetime if I use a array

        void PrepareIds()
        {
        for(int i=0;i<10240;i++)
        m_vecAvailableIds.push_back(i);

        }

        int FetchId()
        {
        boost::lock_guard lock(m_lock);
        if(m_vecAvailableIds.size()<=0)
        return -1;

        int nId =  m\_vecAvailableIds.back();
        m\_vecAvailableIds.pop\_front();
            return nId;
        

        }

        int ReturnId(int nId)
        {
        boost::lock_guard lock(m_lock);
        m_vecAvailableIds.push_back(nId);
        }

        bool Connected(std::string strIp)
        {
        int nNewId = FetchId();
        if(nNewId == -1)
        return false;

        CLIENT\_DATA\* pData = m\_arrClients\[nNewId\];
            boost::lock\_guard lock(pData->m\_mutex\_lock);
            pData->m\_bInUse = true;
        pData->m\_nOnlineTime = 0;	
        pData->m\_strIP = strIp;
        

        }

        bool Disconnected(int nClientId)
        {
        Assert(nClientId>=0 && nClientId<10240);

            CLIENT\_DATA\* pData = m\_arrClients\[nClientId\];
            boost::lock\_guard lock(pData->m\_mutex\_lock);
            pData->m\_bInUse
        
        1 Reply Last reply
        0
        • B bestbear

          struct CLIENT_DATA
          {
          int m_nOnlineTime;
          int m_nCredits;
          };

          for a tcp server which would handle at most 10240 clients. I want to manage all the clients.there are two solutions 1: use a std:map, and a mutex over all map operation 2: use a C array. and assign an ID(0-10239) for each client if connected,If disconnected,the Id would be recycled. if I use an array,mutex would only be necessary over the ID operations.such as assign an Id to a client when connected,recycle an Id when a client is disconnected. in fact,they are not different if I only have to handle connect or disconnect. but if I want to change the CLIENT_DATA for each client. for the first solution:I have to lock the whole map; for the second, I could maintain a mutex in each CLIENT_DATA. my question is, solution 1 is much more easy to code.solution 2 seems much more efficient. which one do you prefer? Thank you.

          J Offline
          J Offline
          Jochen Arndt
          wrote on last edited by
          #4

          Some thoughts about your posts (the initial one and the above reply to Afzaal Ahmad Zeeshan). Do you really need to store the IP? If so, don't store it as string. There is no need to generate a (re-usable) connect ID. You already have one: The connection socket handle. Using the handle avoids also storing the IP because you can get the IP from the handle using getpeername. But using the handle makes using a map more appropriate. There is also a solution to avoid locking at all: Just let the functions be executed in the same thread. As far as I understand there are three events: connection, disconnection, and periodical updates. If connection and disconnection are events issued from other threads, implement signaling functions passing the socket handle. My suggestion: Use a map storing the socket handle and avoid locking by putting all associated functions into a single thread.

          B 1 Reply Last reply
          0
          • J Jochen Arndt

            Some thoughts about your posts (the initial one and the above reply to Afzaal Ahmad Zeeshan). Do you really need to store the IP? If so, don't store it as string. There is no need to generate a (re-usable) connect ID. You already have one: The connection socket handle. Using the handle avoids also storing the IP because you can get the IP from the handle using getpeername. But using the handle makes using a map more appropriate. There is also a solution to avoid locking at all: Just let the functions be executed in the same thread. As far as I understand there are three events: connection, disconnection, and periodical updates. If connection and disconnection are events issued from other threads, implement signaling functions passing the socket handle. My suggestion: Use a map storing the socket handle and avoid locking by putting all associated functions into a single thread.

            B Offline
            B Offline
            bestbear
            wrote on last edited by
            #5

            thank you in fact there are two threads. Thread A would get some CLIENT_DATA pointer to do something frequently,but would not change the map Thread B Is the update thread include handling connect and disconnect,the map would only be changed here. so If I update the map in thread B, It should be locked while updating. it would block the Thread A at somewhere like GetClientData(int nClientId); solution 2 is designed to avoid locking the whole CLIENT_DATA collection in Thread B. my question is: If the map is not vary large,use a std::map is fine,but if the collection of CLIENT_DATA is very large, such as 10240,Is std::map ok?

            J 1 Reply Last reply
            0
            • B bestbear

              thank you in fact there are two threads. Thread A would get some CLIENT_DATA pointer to do something frequently,but would not change the map Thread B Is the update thread include handling connect and disconnect,the map would only be changed here. so If I update the map in thread B, It should be locked while updating. it would block the Thread A at somewhere like GetClientData(int nClientId); solution 2 is designed to avoid locking the whole CLIENT_DATA collection in Thread B. my question is: If the map is not vary large,use a std::map is fine,but if the collection of CLIENT_DATA is very large, such as 10240,Is std::map ok?

              J Offline
              J Offline
              Jochen Arndt
              wrote on last edited by
              #6

              So you have these conditions: connect and disconnect Seldom, single add / remove. Locking is no problem. update Periodically, all items must be accessed. Locking is a problem when updating requires a significant time. query Single? access in peridocally? short/long? intervals. If locking is a problem depends on query frequency and number of items. So it seems that only updating is critical. But as I understood you will update all items at once and know the max. number of items. Regardless of the choosen storage type, the first optimisation is reserving the required memory to avoid re-allocations and avoid members that use dynamic memory allocation like std::string. So your requirements are:

              • Inserting and deleting performance is not critical
              • Iterating over all items is critical
              • Accessing single items is not critical?

              When using a map, use an unordered_map because it satifies the above (fast iterating over all elements but slow iterating over a subset of the elements). When using an array, list, or vector, you have to perform a find to access single elements (which is also there but hidden when using a map). When using a pre-allocated C array you have to implement also functions to add and remove elements where adding is simple (append) but removing requires moving memory. But this will be probably the fastest option when iterating over all items. But I don't think that the performance of a plain C array is much better than using a container iterator (note that you must use the iterator rather then using the at or [] operator because that result in a lookup with maps and include out of range checks with other container types). You may implement different versions and benchmark them to see the differences. But a max. number of 10240 should be not critical.

              B 1 Reply Last reply
              0
              • J Jochen Arndt

                So you have these conditions: connect and disconnect Seldom, single add / remove. Locking is no problem. update Periodically, all items must be accessed. Locking is a problem when updating requires a significant time. query Single? access in peridocally? short/long? intervals. If locking is a problem depends on query frequency and number of items. So it seems that only updating is critical. But as I understood you will update all items at once and know the max. number of items. Regardless of the choosen storage type, the first optimisation is reserving the required memory to avoid re-allocations and avoid members that use dynamic memory allocation like std::string. So your requirements are:

                • Inserting and deleting performance is not critical
                • Iterating over all items is critical
                • Accessing single items is not critical?

                When using a map, use an unordered_map because it satifies the above (fast iterating over all elements but slow iterating over a subset of the elements). When using an array, list, or vector, you have to perform a find to access single elements (which is also there but hidden when using a map). When using a pre-allocated C array you have to implement also functions to add and remove elements where adding is simple (append) but removing requires moving memory. But this will be probably the fastest option when iterating over all items. But I don't think that the performance of a plain C array is much better than using a container iterator (note that you must use the iterator rather then using the at or [] operator because that result in a lookup with maps and include out of range checks with other container types). You may implement different versions and benchmark them to see the differences. But a max. number of 10240 should be not critical.

                B Offline
                B Offline
                bestbear
                wrote on last edited by
                #7

                thank you very much I would try and test it.

                1 Reply Last reply
                0
                Reply
                • Reply as topic
                Log in to reply
                • Oldest to Newest
                • Newest to Oldest
                • Most Votes


                • Login

                • Don't have an account? Register

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • World
                • Users
                • Groups