Archived

This forum has been archived. Please start a new discussion on GitHub.

ICE Windows Service

I'm getting overwhelmed and is now doubting myself so I'll just describe what I want to do and wait for your opinions.

More than a year ago, I made a ICE prototype to allow client server communication for the freely available J programming language . Since I again have time on my hands, I would like to convert my ICE server code to a Window Service.

My requirement is very simple which is:
  1. Modify existing ICE server code to run when windows startup, even if there is no account logged on.
  2. Have a facility to STOP and START/RESTART the ICE server.
  3. (Optional) Can be interfaced with MS-Windows Services Window

Looking at the ICE documentation, my gut reaction was that IcePack was the way to go. After 2 days of research, I now feel that I may going the wrong way.

What do you guys think of my little problem? Do you think I should really build an honest to goodness C++ Service or ICE already have this facilty and I'm just too dumb to use it? Any help in this matter is highly appreciated.

r/Alex

Comments

  • bernard
    bernard Jupiter, FL
    Hi Alex,

    If you just want a Windows service, you should look instead at the Ice::Service class, described in 10.3.2 of the Ice 1.4 documentation.

    Use IcePack if you want IcePack to start your server "on demand", and introduce an indirection between your clients and server.

    Cheers,
    Bernard
  • Wow! Thanks Bernard.

    I actually didn't know that there was an Ice::Service class. This is exactly what I was looking for. I was fooling around with IcePack and I was being bothered by the indirection capabilites (which is overkill for what I was trying to test).

    Is this a new thing? Cause I don't seem to remember this capability when I actually read the documentation (it was Ice 1.0) more than a year ago. I lost that copy and I'm sort of working from memory. ;)

    Eitherway, thanks! This definitely points me in the right direction.

    r/Alex
  • Here's one more reason why I really like ICE. Converting your ICE console server to a Windows Service is a snap. You only have to change a few lines of code.

    Take for example my code. Here is the original ICE console server:
    #include <Ice/Ice.h>
    #include <Ice/Stats.h>
    #include <jSocketsI.h>
    #include "jsvr.h"
    
    using namespace std;
    
    class jSocketsStats : public virtual Ice::Stats {
    public:
    	virtual void bytesSent (const std::string &prot, Ice::Int num)
    	{
    		cout << prot << ": sent " << num << " bytes" << endl;
    	};
    
    	virtual void bytesReceived(const std::string &prot, Ice::Int num)
    	{
    		cout << prot << ": received " << num << " bytes" << endl;
    	};
    };
    
    class IceServer : virtual public Ice::Application {
    public:
    	virtual int run(int argc, char* argv[]) {
    		// Get the passed parameter
    		jsvFileName(argv[1]);
    		
    		// Server code
    		Ice::ObjectAdapterPtr adapter = 
    			communicator()->createObjectAdapterWithEndpoints(
    				"jclCommandAdapter", "default -p 7012 -z");
    		Ice::ObjectPtr object = new jSocketsI;
    		adapter->add(object,
    			Ice::stringToIdentity("jclCommand"));
    		adapter->activate();
    		
    		// Lets activate the status class too
    		Ice::StatsPtr stats = new jSocketsStats;
    		communicator()->setStats(stats);
    
    		// Wait until all operations are completed
    		communicator()->waitForShutdown();
    		if (interrupted()) {
    			cerr << appName() 
    				<< ": received signal, shutting down" << endl;
    		}
    		return 0;
    	};
    };
    
    int main(int argc, char* argv[]) {
    	IceServer app;
    	return app.main(argc,argv);
    }
    

    Now here is my new Windows Service:
    #include <Ice/Ice.h>
    #include <Ice/Service.h>
    #include <jSocketsI.h>
    #include "jsvr.h"
    
    using namespace std;
    
    class IceService : virtual public Ice::Service {
    protected:
    	virtual bool start(int, char *[]);
    private:
    	Ice::ObjectAdapterPtr _adapter;
    };
    
    bool IceService::start(int argc, char *argv[]) {
        // Get the passed parameter
    	jsvFileName(argv[1]);
    
    	_adapter = communicator()->createObjectAdapterWithEndpoints(
    			"jclCommandAdapter", "default -p 7012");
    	Ice::ObjectPtr object = new jSocketsI;
    	_adapter->add(object,
    			Ice::stringToIdentity("jclCommand"));
    	_adapter->activate();
    	
    	return true;
    }
    
    int main(int argc, char* argv[]) {
    	IceService svc;
    	return svc.main(argc,argv);
    }
    

    The amazing thing is, I didn't have to change any other code in my application. I didn't even need to recompile my ICE Client. :)

    Good job ZeroC.

    r/Alex
  • marc
    marc Florida
    Thanks, I'm glad you like it :)
  • Oh ... and another thing I really liked is the use of Windows Event Log. You'll notice that my new service code is smaller than the original console server. This is because I realize I didn't need the Ice::Stats and just used an Ice.Config file. The config file actually allows for a granular control on what information can be logged.

    Here's the Ice.Config file I'm using:
    // iceJLibSrv.CFG
    // ICE JLibrary Server Configuration File
    
    // The network trace level:
    // 0 No network trace. (default)
    // 1 Trace connection establishment and closure.
    // 2 Like 1, but more detailed.
    // 3 Like 2, but also trace data transfer.
    Ice.Trace.Network=2
    
    // The protocol trace level:
    // 0 No protocol trace. (default)
    // 1 Trace Ice protocol messages.
    Ice.Trace.Protocol=0
    
    // 
    // 0 No request retry trace. (default)
    // 1 Trace Ice operation call retries.
    // 2 Also trace Ice endpoint usage.
    Ice.Trace.Retry=1
    
    // The slicing trace level:
    // 0 No trace of slicing activity. (default)
    // 1 Trace all exception and class types that are unknown to the
    // 	receiver and therefore sliced.
    Ice.Trace.Slicing=1
    
    // If set to a value larger than zero, Ice applications will print warning
    // messages for certain exceptional conditions in connections. The default value is 0.
    Ice.Warn.Connections=1
    
    // If set to a value larger than zero, servers will print a warning message if
    // they receive a datagram that exceeds the servers' receive buffer size. (Note that
    // this condition is not detected by all UDP implementations -- some implementations
    // silently drop received datagrams that are too large.) The default value is 0.
    Ice.Warn.Datagrams=1
    
    // If set to a value larger than zero, Ice applications will print warning
    // messages for certain exceptions that are raised while an incoming request is
    // dispatched.
    // 0 No warnings.
    // 1 Print warnings for unexpected Ice::LocalException,
    // 	Ice::UserException, C++ exceptions,
    // 	exceptions. (default)
    // 2 Like 1, but also issue warnings for
    // 	Ice::ObjectNotExistException,
    // 	Ice::FacetNotExistException, and
    // 	Ice::OperationNotExistException.
    Ice.Warn.Dispatch=2
    
    // If set to a value larger than zero, warnings are printed if an AMI callback
    // raises an exception. The default value is 1.
    Ice.Warn.AMICallback=1
    
    // If set to a value larger than zero, the Ice::Communicator destructor will
    // print a warning if some other Ice-related C++ objects are still in memory. The
    // default value is 1. (C++ only.)
    Ice.Warn.Leaks=1
    
    // This property controls the maximum size (in kilobytes) of a protocol message that
    // will be accepted or sent by the Ice run time. The size includes the size of the Ice
    // protocol header. Messages larger than this size cause a [MemoryLimitException].
    // The default size is 1024 (1 Megabyte). Settings with a value less than 1 are
    // ignored.
    // This property adjusts the value of Ice.UDP.RcvSize and Ice.UDP.SndSize,
    // that is, if Ice.UDP.RcvSize or Ice.UDP.SndSize are larger than Ice.Message-
    // SizeMax * 1024 + 28, they are adjusted to Ice.MessageSizeMax * 1024 + 28.
    Ice.MessageSizeMax=1024
    
    // If set to a value larger than zero, a special logger is installed that logs to the
    // Windows Event Log instead of standard error. The event source name is the value
    // of Ice.ProgramName. (Windows 2000/XP only.)
    Ice.UseEventLog=1
    
    // If set to a value larger than zero, the output of the default logger will
    // include timestamps.
    Ice.Logger.Timestamp=1
    

    The attachment below show my PC's event log and you can see that my JLibSRV has both information and warning events.

    ICE really make a lot of things easier for server development. Thanks and more power to ZeroC! :)

    r/Alex

    edit: I mistakenly posted my actual/real email address. Heheheheh