Archived

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

icebox and adapters

Hi,

I have a small problem concerning IceStorm, IceBox and ObjectsAdapters.

This is my setup:

In my main function I run:

// Fork new process
pid_t pid;
pid = fork();
if(pid < 0) {
exit(EXIT_FAILURE);
}
switch(pid) {

// Child
case 0 :

// Execute application
execl("/usr/bin/icebox", "/usr/bin/icebox", "--Ice.Config=config.icebox", 0);
break;

// Parent
default :
break;
}

do {
try {
obj = communicator->stringToProxy("IceStorm/TopicManager:tcp -p 10001");
topicManager = IceStorm::TopicManagerPrx::checkedCast(obj);
} catch(const Ice::Exception& ex) {
//Loop and ignore all exceptions until the Notification Service is found
sleep(2);
}
} while (topicManager == 0);

This starts the IceStorm and works as it should. But when I shutdown the communicator, the icebox process stays alive, what is not quite bad.

When I start my Ice-programm again I get now the:

Network.cpp:475: Ice::SocketException:
socket exception: Address already in use

error message. When I run 'netstat -an |grep 10000' I get the following:

tcp 0 0 31.3.21.95:10000 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:10000 0.0.0.0:* LISTEN

I don't get this behaviour, when I start icebox from the console.

Where is my error or did I misunderstood something?

Comments

  • benoit
    benoit Rennes, France
    Hi,

    This exception:
    Network.cpp:475: Ice::SocketException:
    socket exception: Address already in use

    indicates that an object adapter couldn't listen on a given port because it's already in use. What is listening on port 10000? If it's the IceStorm service, I would expect to get this error if you don't shut it down before to restart it.

    Btw, why do you fork/exec the icebox process for IceStorm in your application? It would be simpler to use IceGrid if you don't want to manually start IceStorm on the command line :). An other option would be to implement a service for your application and host your service within the same IceBox server as the IceStorm service.

    Cheers,
    Benoit.
  • Hi,

    thanks for the reply, you zeroc guys answer quite fast to a lot of questions here.

    The IceStorm runs on port 10001, but the port 10000 is kept open. That might be because I haven't shutdown the publisher corretly. How do I do that?

    The forking is for design reasons. I want to compare CORBA and ICE for a thesis and for this reason I want to keep as much code the same as for the CORBA implementation.

    Till now ICE is much better to code and ICeStorm is nice to use.

    Hm this doesn't belong in this forum, but can you tell me, where I can get information about the maturity and code status of ICE?
  • benoit
    benoit Rennes, France
    Hi,

    You should provide more information on your application (describe the different components, post the configuratin files of each components, etc), I'm afraid it's difficult to help otherwise.

    A publisher simply invokes on the IceStorm service to publish updates and doesn't need to listen on any ports so I'm not sure why you think it's your publisher that is the cause of this exception.

    Or are you talking about the IceStorm publish endpoints here? Terminating the IceBox process should free all the ports. To terminate this process, you can use the iceboxadmin utility or, on Unix, send the SIGTERM signal to the process.

    Otherwise, we don't really have any additional information other than our web site and these forums to show that Ice is mature. All I can tell you is that it's used in many projects and production environments (see here for some of them) and that there was no major API changes and no protocol changes since Ice 1.0 was released. The best is to judge by yourself by using it :).

    Cheers,
    Benoit.
  • Sure, here is the code and the configuration:

    First the icebox/icestorm config:

    config.icebox:

    #
    # The IceBox server endpoint configuration
    #
    IceBox.ServiceManager.Endpoints=tcp -p 9998

    #
    # The IceStorm service
    #
    IceBox.Service.IceStorm=IceStormService,31:createIceStorm --Ice.Config=config.service

    #
    # Warn about connection exceptions
    #
    #Ice.Warn.Connections=1

    #
    # Network Tracing
    #
    # 0 = no network tracing
    # 1 = trace connection establishment and closure
    # 2 = like 1, but more detailed
    # 3 = like 2, but also trace data transfer
    #
    #Ice.Trace.Network=1

    #
    # Protocol Tracing
    #
    # 0 = no protocol tracing
    # 1 = trace protocol messages
    #
    #Ice.Trace.Protocol=1

    now the config.service:

    #
    # This property is used by the administrative client to connect to IceStorm.
    #
    IceStorm.TopicManager.Proxy=IceStorm/TopicManager:default -p 10001

    #Ice.Trace.Network=2

    #
    # This property defines the endpoints on which the IceStorm
    # TopicManager listens.
    #
    IceStorm.TopicManager.Endpoints=default -p 10001

    #
    # The IceStorm service instance name.
    #
    IceStorm.InstanceName=IceStorm

    #
    # This property defines the endpoints on which the topic
    # publisher objects listen.
    #
    IceStorm.Publish.Endpoints=default

    #
    # TopicManager Tracing
    #
    # 0 = no tracing
    # 1 = trace topic creation, subscription, unsubscription
    # 2 = like 1, but with more detailed subscription information
    #
    IceStorm.Trace.TopicManager=2

    #
    # Topic Tracing
    #
    # 0 = no tracing
    # 1 = trace unsubscription diagnostics
    #
    IceStorm.Trace.Topic=1

    #
    # Subscriber Tracing
    #
    # 0 = no tracing
    # 1 = subscriber diagnostics (subscription, unsubscription, event
    # propagation failures)
    #
    IceStorm.Trace.Subscriber=1

    #
    # Flush Tracing (for batch mode transfer flushing)
    #
    # 0 = no tracing
    # 1 = trace activity of flusher thread
    #
    IceStorm.Trace.Flush=1

    #
    # Amount of time in milliseconds between flushes for batch mode
    # transfer. The minimum allowable value is 100ms.
    #
    IceStorm.Flush.Timeout=2000

    #
    # Network Tracing
    #
    # 0 = no network tracing
    # 1 = trace connection establishment and closure
    # 2 = like 1, but more detailed
    # 3 = like 2, but also trace data transfer
    #
    #Ice.Trace.Network=1

    #
    # This property defines the home directory of the Freeze
    # database environment for the IceStorm service.
    #
    Freeze.DbEnv.IceStorm.DbHome=db

    Here is the code (snipped):

    publisher:

    int main(int argc, char *argv[])
    {
    try {
    communicator = Ice::initialize(argc, argv);
    } catch(const Ice::Exception& ex) {
    return EXIT_FAILURE;
    }

    Ice::ObjectAdapterPtr adapter;
    try {
    adapter = communicator->createObjectAdapterWithEndpoints("PublisherAdapter", "default -p 10000");
    } catch(const Ice::Exception& ex) {
    return EXIT_FAILURE;
    }

    if (adapter == 0) return EXIT_FAILURE;

    try {
    adapter->activate();
    } catch(const Ice::Exception& ex) {
    return EXIT_FAILURE;
    }

    IceStorm::TopicManagerPrx topicManager;
    Ice::ObjectPrx obj;
    IceStorm::TopicPrx topic1;
    try {
    obj = communicator->stringToProxy("IceStorm/TopicManager:tcp -p 10001");
    topicManager = IceStorm::TopicManagerPrx::checkedCast(obj);

    } catch(const Ice::Exception& ex) {

    //If no channel is found create one

    // Fork new process
    pid_t pid;
    pid = fork();
    if(pid < 0) {
    exit(EXIT_FAILURE);
    }
    switch(pid) {

    // Child
    case 0 :

    // Execute application
    execl("/usr/bin/icebox", "/usr/bin/icebox", "--Ice.Config=config.icebox", 0);
    break;

    // Parent
    default :
    break;
    }

    do {
    try {
    obj = communicator->stringToProxy("IceStorm/TopicManager:tcp -p 10001");
    topicManager = IceStorm::TopicManagerPrx::checkedCast(obj);
    } catch(const Ice::Exception& ex) {
    sleep(2);
    }
    } while (topicManager == 0);

    }

    try {
    topic = topicManager->retrieve("EC");
    }
    catch(const IceStorm::NoSuchTopic&) {
    topic = topicManager->create("EC");
    }

    try {
    Ice::ObjectPrx pub = topic->getPublisher();
    ec = ManagedNodePrx::uncheckedCast(pub);

    }
    catch(const Ice::Exception& ex) {
    }

    communicator->waitForShutdown();
    return EXIT_SUCCESS;
    }

    and now the subscriber:

    Ice::CommunicatorPtr communicator;
    try {
    communicator = Ice::initialize(argc, argv);
    } catch(const Ice::Exception& ex) {
    return EXIT_FAILURE;
    }

    Ice::ObjectAdapterPtr adapter;
    try {
    adapter = communicator->createObjectAdapterWithEndpoints("subscriberAdapter", "tcp -p 10002");
    } catch(const Ice::Exception& ex) {
    return EXIT_FAILURE;
    }

    if (adapter == 0) return EXIT_FAILURE;

    try {
    adapter->activate();
    } catch(const Ice::Exception& ex) {
    return EXIT_FAILURE;
    }

    IceStorm::TopicManagerPrx topicManager;
    Ice::ObjectPrx obj;
    IceStorm::TopicPrx topic;
    try {
    obj = communicator->stringToProxy("IceStorm/TopicManager:tcp -p 10001");
    topicManager = IceStorm::TopicManagerPrx::checkedCast(obj);

    } catch(const Ice::Exception& ex) {

    }

    try {
    topic = topicManager->retrieve("'EC");
    }
    catch(const IceStorm::NoSuchTopic&) {
    topic = topicManager->create("EC");
    }

    IceStorm::QoS qos;
    topic->subscribe(qos, thisproxy);

    communicator->waitForShutdown();

    exit(EXIT_SUCCESS);
    }


    BTW is there a possibility to define adapters and endpoints without setting a port? I will have a more or less dynamical structure and I don't know how many programs and adapters will run on one machine in my set-up.
  • benoit
    benoit Rennes, France
    Hi,

    The problem comes from the your fork/exec code. After creating the publisher object adapter (which is listening on port 10000), you fork/exec the icebox server but don't close the file descriptors (in the child process) so the child icebox process still listens on port 10000 even if your publisher process is gone. You should close all the file descriptors inherited from the parent in the child process after the fork() and before the exec().

    Depending on your application, you can omit the setting of the port in the object adapter endpoints (e.g.: you don't need to set an endpoint for the objet adapter of your subscribers since your subscribers are transient). See section 32.4.6 Endpoints in the Ice manual for more information on object adapter endpoints.

    Cheers,
    Benoit.
  • Many thanks for your answers. That helps me alot.