How do check out IB's connection

The C++ API in IB may be structures differently (have not looked at your c++ code in detail) but the IsConnected method in c# is indeed utterly useless. One has to implement something on his one.

Further how IB's API disconnects is a disgrace. Invoking disconnect basically throws errors because the socket is disconnected but the while loop that polls the socket is not exited.

There are truly some very strange things the IB coders either don't understand, or did not have time to implement, or are incapable of implementing.

No biggies for a capable coder to circumvent but true annoyances.

I had a similar problem and combed through the code a little while back.

An isConnected() method exists in the test files, and is implemented as follows. I'm running C++ v9.72.14, and it does pretty much what you're looking for. You don't say what version (or what language) you're using, but this example may help you.

Main.cpp: note how the while(client.isConnected) statement is called win the endless for (;;) loop. This is basically the keep-alive previously discussed.

Code:
    for (;;) {
        ++attempt;
        printf( "Attempt %u of %u\n", attempt, MAX_ATTEMPTS);
        TestCppClient client(clientId, category, ticker, shares, bid, ask, stop);
        if(connectOptions) {
            client.setConnectOptions(connectOptions);
        }
        printf( "client.connect result: %d\n", client.connect(host, port, clientId));
        while( client.isConnected()) {
            client.processMessages();
        }
        if( attempt >= MAX_ATTEMPTS) { break;}
        printf( "Sleeping %u seconds before next attempt\n", SLEEP_TIME);
        sleep( SLEEP_TIME);
    }
    printf ( "End of C++ Socket Client Test\n");

After the class TestCppClient is instantiated, the isConnected() method is available on the interface. Here is the definition:

Code:
bool TestCppClient::isConnected() const
{
    return m_pClient->isConnected();
}

So you should be able to use this provided method. Just instantiate the class, and call the method.

If you really want (or need) to get in deeper, there is more:

From TestCppClient.h:
m_pClient is pointer to an instance of EClientSocket.

Code:
private:
    //! [socket_declare]
    EClientSocket * const m_pClient;

EClientSocket.h
EClientSocket inherits from both EClient and EClientMsgSink:

Code:
class TWSAPIDLLEXP EClientSocket : public EClient, public EClientMsgSink
{

EClient: There's a few public methods here that may help.

Code:
EClient::ConnState EClient::connState() const
{
    return m_connState;
}

bool EClient::isConnected() const
{
    return m_connState == CS_CONNECTED;
}

bool EClient::isConnecting() const
{
    return m_connState == CS_CONNECTING;
}

Note that ConnState is an enum. Perhaps the connState() method may be of use? Not that ConnState is an enum:

Code:
    enum ConnState {
        CS_DISCONNECTED,
        CS_CONNECTING,
        CS_CONNECTED,
        CS_REDIRECT
    };

EClient.cpp
The actual connection request is in the following method. It is protected, so note that you're getting pretty deep in here.

Code:
int EClient::sendConnectRequest()
{
    m_connState = CS_CONNECTING;

    int rval;

    // send client version
    std::stringstream msg;
    if( m_useV100Plus) {
        msg.write( API_SIGN, sizeof(API_SIGN));
        prepareBufferImpl( msg);
        if( MIN_CLIENT_VER < MAX_CLIENT_VER) {
            msg << 'v' << MIN_CLIENT_VER << ".." << MAX_CLIENT_VER;
        }
        else {
            msg << 'v' << MIN_CLIENT_VER;
        }
        if( !m_connectOptions.empty()) {
            msg << ' ' << m_connectOptions;
        }

        rval = closeAndSend( msg.str(), sizeof(API_SIGN));
    }
    else {
        ENCODE_FIELD( CLIENT_VERSION);

        rval = bufferedSend( msg.str());
    }

    m_connState = rval > 0 ? CS_CONNECTED : CS_DISCONNECTED;

    return rval;
}

You could dig into the closeAndSend() method from here...
 
The C++ API in IB may be structures differently (have not looked at your c++ code in detail) but the IsConnected method in c# is indeed utterly useless. One has to implement something on his one.

Further how IB's API disconnects is a disgrace. Invoking disconnect basically throws errors because the socket is disconnected but the while loop that polls the socket is not exited.

There are truly some very strange things the IB coders either don't understand, or did not have time to implement, or are incapable of implementing.

No biggies for a capable coder to circumvent but true annoyances.

Are you using v9.72? I'm experiencing the same issue as described here in the API Yahoo group after moving from 9.71 to 9.72, which also sounds a lot like you describe when you say "Invoking disconnect basically throws errors because the socket is disconnected but the while loop that polls the socket is not exited."

Can you share your fix or at least point to where this loop is so I can get a look at it? Thanks!
 
I don't have the code in front of me right now but you can either catch the error and handle it (which if memory serves was the proposed solution in the API Yahoo group, which by the way is the authority in anything IB API related), or else you can use the source code and replace some of the socket code with your own improved version. Downside of that is that you need to carry those changes over to each newly released API version.

I myself ended up writing my own poller and that poller within a while loop exits as soon as the "Disconnect()" is invoked and only then will the socket be gracefully disconnected and closed and subsequently disposed. That is what worked for me.

Are you using v9.72? I'm experiencing the same issue as described here in the API Yahoo group after moving from 9.71 to 9.72, which also sounds a lot like you describe when you say "Invoking disconnect basically throws errors because the socket is disconnected but the while loop that polls the socket is not exited."

Can you share your fix or at least point to where this loop is so I can get a look at it? Thanks!
 
Hi guys. Just wanted to contribute my workaround on this thread, since it appears it's the *only* one I could find about IB's API's lost-connection issue. I hope to save some other people some headache. And yes, the failure of .isConnected() has cost me 5-digit losses before.

The workaround uses objEClientSocket.reqCurrentTime() to trigger a response at objEWrapper.currentTime(long time). The EWrapper then keeps track of the most-recent time returned by objEWrapper.currentTime(long time), and can return the number of seconds that has passed since the last full User -> TWS -> IB connection was made.
For this, I extended EWrapper (to let's say, BenWrapper), and added the method:
public long BenWrapper.getSecondsSinceLastContactWithTWSOrIB() {..return seconds since last contact here..}

Then, the user's own connection poller repeatedly calls objEClientSocket.reqCurrentTime() at the poller's set interval, and at the same time, it checks how long a suspected disconnect has lasted (60secs? 90secs?,etc), and then force a reconnect via EClientSocket.eConnect(...) once that limit has passed.


And so, my EWrapperAdapter....
Code:
public class IBWrapperAdapter implements EWrapper {

private long mostRecentTimeOfServerResponseInSec = System.currentTimeMillis()/1000L;

...

/**
     * Returns the last time the TWS server could pull the time from IB's servers
     * via EClientSocket.reqCurrentTime().
     * For this method to work as expected, the user must call EClientSocket.reqCurrentTime()
     * on a regular basis. This will act somewhat of a "heartbeat", to ensure a the
     * connection status of API -> TWS -> IB Servers.
     * @return
     */
    public long getMostRecentTimeOfServerResponseInSec() {
        return this.mostRecentTimeOfServerResponseInSec;
    }
    public long getSecondsSinceLastContactWithTWSOrIB() {
        return System.currentTimeMillis()/1000L - this.getMostRecentTimeOfServerResponseInSec();
    }
    public void resetSecondsSinceLastContactWithTWSOrIB() {
        this.mostRecentTimeOfServerResponseInSec = System.currentTimeMillis()/1000L;
    }

...
}

And the connection poller.....
Code:
private class TWSConnectionPoller implements Runnable {
        public TWSConnectionPoller() {
        }
        public void run() {
            // ibSocket.reqCurrentTime() lets IBWrapperAdapter know when the last
            // successful contact with IB's servers was.
            ibSocket.reqCurrentTime();
            if (!ibSocket.isConnected()) {
                logger.info("Weird. Connection to TWS is disconnected.");
                /**
                 *  If we're going to reset this connection, we need a new ClientID
                 */
                twsClientID = new Random().nextInt(100000) * 10000 + 1; // ID used by TWS to identify this connection
                logger.info("Connecting to TWS on {} port {} with clientID {}", twsHost, twsHostPortNumber, twsClientID);
                ibSocket.eConnect(twsHost, twsHostPortNumber, twsClientID);
                if (!ibSocket.isConnected()) {
                    logger.warn("TWSConnectionPoller couldn't reconnect to {} on port {}", twsHost, twsHostPortNumber);
                } else {
                    logger.warn("Reconfirming all PricedAsset Positions");
                    reconfirmAllPricedAssetPositions();
                }
            }
            long secondsSinceLastContact = objIBWrapperAdapter.getSecondsSinceLastContactWithTWSOrIB();
            //System.out.println("Difference between now and last server contact is = " + secondsSinceLastContact + " seconds");
            if (secondsSinceLastContact > 60) {
                // force the EClientSocket into a disconnected state, so the .isConnected() above will actually work.
                ibSocket.eDisconnect();
                // reset the seconds counter to 0, so we'll try reconnecting (if still disconnected) in another 60 seconds.
                objIBWrapperAdapter.resetSecondsSinceLastContactWithTWSOrIB();
            }
        }
    }

Might not be as elegant as some other solutions, but the idea is simple enough to implement
Hope this helps some people prevent some future losses.
 
Back
Top