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#
  4. No problem.. just more of "What would you do" question..

No problem.. just more of "What would you do" question..

Scheduled Pinned Locked Moved C#
databasesysadminagentic-aidata-structureshelp
9 Posts 2 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.
  • J Offline
    J Offline
    Jacob D Dixon
    wrote on last edited by
    #1

    I'm working on one of my first client/server applications. Now my idea is the clients will checkin to the server every 30-60 seconds. When the agent first contacts the server, the server will query the database for "pending actions" (that are placed in there by a control center application), and return those to the client. So: Client connects to server (every 60 seconds or so) Server queries database for actions Server returns action Client performs action Client returns data to server Server stores updated data in database Now what I'm doing is passing a serialized object:

    [Serializable]
    public class Operations
    {
    [Flags]
    public enum Tasks
    {
    NULL = 0,
    CHECKIN = 1,
    UPDATE_SERVICES = 2,
    UPDATE_PROCESSES = 3,
    UPDATE_SOFTWARE = 4,
    UPDATE_PRINTERS = 5,
    UPDATE_DEVICES = 6,
    UPDATE_DRIVES = 7,
    UPDATE_SYSTEMBOARD = 8,
    UPDATE_COMPUTERINFO = 9,

            GET\_SERVICES = 10,
            GET\_PROCESSES = 11,
            GET\_SOFTWARE = 12,
            GET\_PRINTERS = 13,
            GET\_DEVICES = 14,
            GET\_DRIVES = 15,
            GET\_SYSTEMBOARD = 16,
            GET\_COMPUTERINFO = 17,
            GET\_ALL\_DATA = 18,
    
            REGISTER\_AGENT = 19
        }
    
        public int AgentId { get; set; }
        public int AgentLocation { get; set; }
        public string Netbios { get; set; }
    
        public Tasks Task { get; set; }
        public ComputerInfo ComputerInfo { get; set; }
        public SystemBoard SystemBoard { get; set; }
        public Processes\[\] Processes { get; set; }
        public IPAddress\[\] IpAddresses { get; set; }
        public Services\[\] Services { get; set; }
        public DiskDrive\[\] DiskDrives { get; set; }
    }
    

    So the client has access to this info as well. So what it does it populate that information. (If the client sets the TASK to UPDATE_SERVICES the client only populates the Services[] array.. not all of the information is populated each time fyi) Now before I sent or receive I Serialize and Deserialize each side:

    IFormatter formatter = new BinaryFormatter();
    Operations[] ops (Operations[])formatter.Deserialize(state.ms);

    BTW this works fine.. just wondering if its the CORRECT or a GOOD way of doing it.

    _ 1 Reply Last reply
    0
    • J Jacob D Dixon

      I'm working on one of my first client/server applications. Now my idea is the clients will checkin to the server every 30-60 seconds. When the agent first contacts the server, the server will query the database for "pending actions" (that are placed in there by a control center application), and return those to the client. So: Client connects to server (every 60 seconds or so) Server queries database for actions Server returns action Client performs action Client returns data to server Server stores updated data in database Now what I'm doing is passing a serialized object:

      [Serializable]
      public class Operations
      {
      [Flags]
      public enum Tasks
      {
      NULL = 0,
      CHECKIN = 1,
      UPDATE_SERVICES = 2,
      UPDATE_PROCESSES = 3,
      UPDATE_SOFTWARE = 4,
      UPDATE_PRINTERS = 5,
      UPDATE_DEVICES = 6,
      UPDATE_DRIVES = 7,
      UPDATE_SYSTEMBOARD = 8,
      UPDATE_COMPUTERINFO = 9,

              GET\_SERVICES = 10,
              GET\_PROCESSES = 11,
              GET\_SOFTWARE = 12,
              GET\_PRINTERS = 13,
              GET\_DEVICES = 14,
              GET\_DRIVES = 15,
              GET\_SYSTEMBOARD = 16,
              GET\_COMPUTERINFO = 17,
              GET\_ALL\_DATA = 18,
      
              REGISTER\_AGENT = 19
          }
      
          public int AgentId { get; set; }
          public int AgentLocation { get; set; }
          public string Netbios { get; set; }
      
          public Tasks Task { get; set; }
          public ComputerInfo ComputerInfo { get; set; }
          public SystemBoard SystemBoard { get; set; }
          public Processes\[\] Processes { get; set; }
          public IPAddress\[\] IpAddresses { get; set; }
          public Services\[\] Services { get; set; }
          public DiskDrive\[\] DiskDrives { get; set; }
      }
      

      So the client has access to this info as well. So what it does it populate that information. (If the client sets the TASK to UPDATE_SERVICES the client only populates the Services[] array.. not all of the information is populated each time fyi) Now before I sent or receive I Serialize and Deserialize each side:

      IFormatter formatter = new BinaryFormatter();
      Operations[] ops (Operations[])formatter.Deserialize(state.ms);

      BTW this works fine.. just wondering if its the CORRECT or a GOOD way of doing it.

      _ Offline
      _ Offline
      _Erik_
      wrote on last edited by
      #2

      If you use Flags attribute for the enum, then the values are absolutely wrong. See this[^]. I think you should remove the Flags attribute on your enum. Regarding to your question, well, you have not given us much information but, at a firt glance, I don't like the architecture you describe. It is not versatile. Any possible future change will cause a lot of compatibility problems.

      J 1 Reply Last reply
      0
      • _ _Erik_

        If you use Flags attribute for the enum, then the values are absolutely wrong. See this[^]. I think you should remove the Flags attribute on your enum. Regarding to your question, well, you have not given us much information but, at a firt glance, I don't like the architecture you describe. It is not versatile. Any possible future change will cause a lot of compatibility problems.

        J Offline
        J Offline
        Jacob D Dixon
        wrote on last edited by
        #3

        Ill read the Flags attribute. I have to be able to send the client agents commands to perform which will return data to the server. From there I plan to have a control panel application that will view that information and also be able to send commands to the agents. Now the agents could be on different networks. Which means that the server cannot create a direct connection to the agents due to them possibly being behind a firewall. So the agent of course has to be the one that first connects to the server. I guess what I'm asking is if you were creating something like this how would you lay it out? I created the Operations class because it can hold the information, but it doesn't mean that ALL the information will be populated. Sorry if I'm not explaining it very well.. lets me try it this way: Client Agent connects to server Server Accepts connection and queries database for pending actions:

        Socket old = iar.AsyncState as Socket;
        Socket client = old.EndAccept(iar);

        // Create Operations objects
        Operations[] ops = AgentActions.GetPendingOperations(1);

        MemoryStream ms = new MemoryStream();
        IFormatter formatter = new BinaryFormatter();
        formatter.Serialize(ms, ops);

        // Send our serialized object back to client
        client.BeginSend(ms.ToArray(), 0, (int)ms.Length, 0, new AsyncCallBack(SendCallback), client);

        The pending actions table is just the AgentId and the TaskId (which matches the ENUM). So at this point the client is receiving information from the server about what actions it should perform:

        // (RECEIVECALLBACK)
        int bytesRead = client.EndReceive(iar);
        if (bytesRead > 0)
        {
        state.ms.Write(state.buffer, 0, bytesRead);
        if (bytesRead == StateObject.BufferSize)
        client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
        else
        {
        state.ms.Seek(0, SeekOrigin.Begin);
        IFormatter formatter = new BinaryFormatter();
        Operations[] ops = (Operations[])formatter.Deserialize(state.ms);

         // from here we go to query the data (Running services, processes, computer information, etc..)
         
         // Once we have that information we send it BACK to the server so the server can store in the DB
        

        }
        }

        Here is my state object:

        public class StateObject
        {
        public Socket workSocket = null;
        public const int BufferSize = 1024;
        public byte[] buffer = new byte[BufferSize];
        public MemoryStream ms = new MemoryStream();
        }

        I hope that helps in ex

        _ 1 Reply Last reply
        0
        • J Jacob D Dixon

          Ill read the Flags attribute. I have to be able to send the client agents commands to perform which will return data to the server. From there I plan to have a control panel application that will view that information and also be able to send commands to the agents. Now the agents could be on different networks. Which means that the server cannot create a direct connection to the agents due to them possibly being behind a firewall. So the agent of course has to be the one that first connects to the server. I guess what I'm asking is if you were creating something like this how would you lay it out? I created the Operations class because it can hold the information, but it doesn't mean that ALL the information will be populated. Sorry if I'm not explaining it very well.. lets me try it this way: Client Agent connects to server Server Accepts connection and queries database for pending actions:

          Socket old = iar.AsyncState as Socket;
          Socket client = old.EndAccept(iar);

          // Create Operations objects
          Operations[] ops = AgentActions.GetPendingOperations(1);

          MemoryStream ms = new MemoryStream();
          IFormatter formatter = new BinaryFormatter();
          formatter.Serialize(ms, ops);

          // Send our serialized object back to client
          client.BeginSend(ms.ToArray(), 0, (int)ms.Length, 0, new AsyncCallBack(SendCallback), client);

          The pending actions table is just the AgentId and the TaskId (which matches the ENUM). So at this point the client is receiving information from the server about what actions it should perform:

          // (RECEIVECALLBACK)
          int bytesRead = client.EndReceive(iar);
          if (bytesRead > 0)
          {
          state.ms.Write(state.buffer, 0, bytesRead);
          if (bytesRead == StateObject.BufferSize)
          client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
          else
          {
          state.ms.Seek(0, SeekOrigin.Begin);
          IFormatter formatter = new BinaryFormatter();
          Operations[] ops = (Operations[])formatter.Deserialize(state.ms);

           // from here we go to query the data (Running services, processes, computer information, etc..)
           
           // Once we have that information we send it BACK to the server so the server can store in the DB
          

          }
          }

          Here is my state object:

          public class StateObject
          {
          public Socket workSocket = null;
          public const int BufferSize = 1024;
          public byte[] buffer = new byte[BufferSize];
          public MemoryStream ms = new MemoryStream();
          }

          I hope that helps in ex

          _ Offline
          _ Offline
          _Erik_
          wrote on last edited by
          #4

          Hmmm, I don't know... I don't like it. I still think this architecture is too rigid. Your current implementation is too concrete and the communication layer depends too much on the concrete types you are using. If you had to add some extra features to the Operations in the future you would be in trouble. Your communication layer should be much more abstract. See SOLID principles[^] for object oriented design. However, if you anticipate that the functional requirements for this application will not change nor grow in the future, then what you have done might be enough.

          J 1 Reply Last reply
          0
          • _ _Erik_

            Hmmm, I don't know... I don't like it. I still think this architecture is too rigid. Your current implementation is too concrete and the communication layer depends too much on the concrete types you are using. If you had to add some extra features to the Operations in the future you would be in trouble. Your communication layer should be much more abstract. See SOLID principles[^] for object oriented design. However, if you anticipate that the functional requirements for this application will not change nor grow in the future, then what you have done might be enough.

            J Offline
            J Offline
            Jacob D Dixon
            wrote on last edited by
            #5

            I'll read what you sent and see if I can figure out a good way to change it differently. I mean I have to pass a custom object between the agent and server. That Operations object is a custom object. So if I ever did updates inthe future I would just add it, and then the server would be updated and agents as well.

            _ 1 Reply Last reply
            0
            • J Jacob D Dixon

              I'll read what you sent and see if I can figure out a good way to change it differently. I mean I have to pass a custom object between the agent and server. That Operations object is a custom object. So if I ever did updates inthe future I would just add it, and then the server would be updated and agents as well.

              _ Offline
              _ Offline
              _Erik_
              wrote on last edited by
              #6

              Yep, I know what you mean. My very first client-server solution architecture was really very similar to yours. It was simple and worked very well, but as requirements grew up the maintenance became a pain in the neck. Every change required a new server version and a new client version, and every new piece of software had to be deployed everywhere within the less period of time, becouse there were usually compatibility issues between the new versions and the old ones, and many other headaches. My last client-server architecture is absolutely different. The communication layer is stable, I mean, no matter what information comes and goes, this layer can handle it without any change. Both, client and server layers can be easily extended: there is no need to recompile them. Still more, there is no need to stop them. Each one of these two sides is a simple application which only has to load or unload plugins. I don't even have to change the database structure. When there is a problem with a plugin I only have to change, recompile and replace its library. Sure, the associated module will not be available during the change, but the rest of the application will keep working.

              J 2 Replies Last reply
              0
              • _ _Erik_

                Yep, I know what you mean. My very first client-server solution architecture was really very similar to yours. It was simple and worked very well, but as requirements grew up the maintenance became a pain in the neck. Every change required a new server version and a new client version, and every new piece of software had to be deployed everywhere within the less period of time, becouse there were usually compatibility issues between the new versions and the old ones, and many other headaches. My last client-server architecture is absolutely different. The communication layer is stable, I mean, no matter what information comes and goes, this layer can handle it without any change. Both, client and server layers can be easily extended: there is no need to recompile them. Still more, there is no need to stop them. Each one of these two sides is a simple application which only has to load or unload plugins. I don't even have to change the database structure. When there is a problem with a plugin I only have to change, recompile and replace its library. Sure, the associated module will not be available during the change, but the rest of the application will keep working.

                J Offline
                J Offline
                Jacob D Dixon
                wrote on last edited by
                #7

                I think I see what your saying but I just can't wrap my head around what I should do. I mean I have to pass a certain data structure because this information will be getting stored in a database. So the columns have to match up some way or another. Unless I'm making the clients pass the SQL commands and parameters along with the values to the server, it only seems like if an update was to happen it would have to update the server and clients.

                1 Reply Last reply
                0
                • _ _Erik_

                  Yep, I know what you mean. My very first client-server solution architecture was really very similar to yours. It was simple and worked very well, but as requirements grew up the maintenance became a pain in the neck. Every change required a new server version and a new client version, and every new piece of software had to be deployed everywhere within the less period of time, becouse there were usually compatibility issues between the new versions and the old ones, and many other headaches. My last client-server architecture is absolutely different. The communication layer is stable, I mean, no matter what information comes and goes, this layer can handle it without any change. Both, client and server layers can be easily extended: there is no need to recompile them. Still more, there is no need to stop them. Each one of these two sides is a simple application which only has to load or unload plugins. I don't even have to change the database structure. When there is a problem with a plugin I only have to change, recompile and replace its library. Sure, the associated module will not be available during the change, but the rest of the application will keep working.

                  J Offline
                  J Offline
                  Jacob D Dixon
                  wrote on last edited by
                  #8

                  You didn't happen to write an article on this did you? I would like to see similiar code so I can better understand what I need to do. As I sit right now I am unable to come up with a better solution than passing my custom object (differnet compiled dll) back and forth. The client sends the custom object, the server reads it, and depending on which task was set it calls a different method to insert the data (or update) into a SQL database.

                  _ 1 Reply Last reply
                  0
                  • J Jacob D Dixon

                    You didn't happen to write an article on this did you? I would like to see similiar code so I can better understand what I need to do. As I sit right now I am unable to come up with a better solution than passing my custom object (differnet compiled dll) back and forth. The client sends the custom object, the server reads it, and depending on which task was set it calls a different method to insert the data (or update) into a SQL database.

                    _ Offline
                    _ Offline
                    _Erik_
                    wrote on last edited by
                    #9

                    No, sorry. Actually I thought about that possibility, but after considering what should be included I noticed it should be too large: it should cover several OOD principles and patterns and a huge application of multitier alchitecture, too large as I said and unfortunately I do not have so much time. Anyway, the success of these designs relies on a good abstraction, and I did write an article which intensely uses abstraction and, though it has nothing to do with client-server communication, maybe it can give you some clues in order to get a better abstraction for your application. Here is the link[^]. In the case you describe, for example, the client should send an abstraction of the custom object, the server should read this abstraction and call always the same method on this abstract object to insert the data. How to send an abstraction of a custom object? Well, design an interface and wrap your custom object within a class which implements this interface. This way your server only needs to look at the interface and invoke its methods, so it can work for any custom object (present or future) if it follows the abstraction rules. It is really hard to explain this here: there are a lot of things involved but, as I said before, the key is a good abstraction.

                    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