微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 java.io.DataInputStream.readInt(EClientSocket) 上调用 EClientSocket 上的 eDisconnect() 时,IB TWS API 有一个 SocketException

如何解决在 java.io.DataInputStream.readInt(EClientSocket) 上调用 EClientSocket 上的 eDisconnect() 时,IB TWS API 有一个 SocketException

要使用盈透证券 (IB) TWS API,我需要编写一个实现 EWrapper 的类。我无法正确断开该类中的套接字连接,即使使用 IB 提供的内置 edisconnect() 方法也是如此。

每当我编写一个实现 EWrapper 的类时,在 edisconnect() 实例上调用 EClientSocket 都会抛出一个 Exception(它被传递给 error(Exception e)...更多详情见下文)。我希望能够正确断开连接,以便我可以在同一个程序中串行连接和断开连接。

考虑以下示例:

public class ConnectionTest {
    public static void main(String[] args) {
        // Create Contract
        Contract contract = new Contract();
        contract.symbol("IBM");
        contract.secType("STK");
        contract.exchange("NYSE");

        TWSCounter twsCounter = new TWSCounter(); // Class I wrote that simply keeps track of ID request numbers
        apiclient apiclient = new apiclient(twsCounter);

        apiclient.connect();
        apiclient.reqContractDetails(contract);
        //apiclient.disconnect(); // commented out for first example
    }
}
public class apiclient implements EWrapper {
    private TWSCounter twsCounter;
    private EClientSocket clientSocket = null;
    private EJavaSignal signal = new EJavaSignal();

    private EReader reader;
    
    // Constructor
    public apiclient(TWSCounter twsCounter) {
        this.twsCounter = twsCounter;
    }
    
    public void connect() {
        // Create a new EClientSocket object
        clientSocket = new EClientSocket (this,signal);
        
        // Connect to the TWS
        clientSocket.eConnect("127.0.0.1",7497,0);
        
        // Pause here for connection to complete
        try {
            while (! (clientSocket.isConnected()));
        } 
        catch (Exception e) {
            e.printstacktrace();
            System.err.println("Error trying to connect to TWS API");
            System.exit(1);
        }

        reader = new EReader(clientSocket,signal);
        reader.start();
        
        // Based on IB sample code in Test.java
        new Thread(() -> {
            while (clientSocket.isConnected()) {
                signal.waitForSignal();

                try {
                    reader.processMsgs();
                } catch(Exception e) {
                    error(e);
                    System.err.println("Error while trying reader.processMsgs()");
                }
                
            }
        }).start();

    }
    
    public void disconnect() {
        clientSocket.edisconnect();
    }

    public void reqContractDetails(Contract contract) {
        clientSocket.reqContractDetails(twsCounter.getNextNumber(),contract);
    }

    @Override
    public void contractDetails(int reqId,ContractDetails contractDetails) {
        System.out.println("conID: " + contractDetails.conid());
    }

    // More methods...

当我运行 ConnectionTest 时,我正确地得到了输出 conID: 8314。然而,程序会无限期地继续运行,直到我在 Eclipse 中通过按下“停止”按钮手动终止它。

如果我在 apiclient.disconnect() 的末尾“取消注释”ConnectionTest,那么程序会断开连接,但会抛出异常。

如何选择覆盖 apiclient 中的错误方法会影响发生的情况。如果它们未被覆盖,则进程会静终止,尽管 Exception

但是,如果 public void error(Exception e) 被如下覆盖,我们会得到以下堆栈跟踪:

public void error(Exception e) {
    e.printstacktrace();
}
java.net.socketException: Socket closed
    at java.net.socketInputStream.socketRead0(Native Method)
    at java.net.socketInputStream.socketRead(UnkNown Source)
    at java.net.socketInputStream.read(UnkNown Source)
    at java.net.socketInputStream.read(UnkNown Source)
    at java.net.socketInputStream.read(UnkNown Source)
    at java.io.DataInputStream.readInt(UnkNown Source)
    at com.ib.client.EClientSocket.readInt(EClientSocket.java:233)
    at com.ib.client.EReader.readSingleMessage(EReader.java:119)
    at com.ib.client.EReader.putMessagetoQueue(EReader.java:79)
    at com.ib.client.EReader.run(EReader.java:57)

我认为问题在于 EReader (EReader extends Thread) 即使在套接字断开连接后也会调用 putMessagetoQueue()。来自EReader

    @Override
    public void run() {
        try {
            // loop until thread is terminated
            while (!isInterrupted()) {
                if (!putMessagetoQueue())
                    break;
            }
        }
        catch ( Exception ex ) {
            //if (parent().isConnected()) {
                if( ex instanceof EOFException ) {
                    eWrapper().error(EClientErrors.NO_VALID_ID,EClientErrors.BAD_LENGTH.code(),EClientErrors.BAD_LENGTH.msg() + " " + ex.getMessage());
                }
                else {
                    eWrapper().error( ex);
                }
                
                parent().edisconnect();
            //}
        } 
        
        m_signal.issueSignal();
    }

修改 apiclient.disconnect() 方法来中断 EReader,但似乎没有帮助:

    public void disconnect() {
        reader.interrupt();
        clientSocket.edisconnect();
    }

在大多数情况下,我能够在没有正确解决此问题的情况下度过难关。然而,我真正想做的是串行连接和断开连接,如以下简化示例所示:

public class ConnectionTest {

    public static void main(String[] args) {
        // Create Contracts
        Contract contract = new Contract();
        contract.symbol("IBM");
        contract.secType("STK");
        contract.exchange("NYSE");

        Contract contract2 = new Contract();
        contract2.symbol("KO");
        contract2.secType("STK");
        contract2.exchange("NYSE");


        TWSCounter twsCounter = new TWSCounter();
        apiclient apiclient = new apiclient(twsCounter);

        apiclient.connect();
        apiclient.reqContractDetails(contract);

        try {
            Thread.sleep(1000);
        } catch (Exception e){
            System.err.println("Couldn't sleep");
            System.exit(1);
        }
        
        apiclient.disconnect();

        try {
            Thread.sleep(1000);
        } catch (Exception e){
            System.err.println("Couldn't sleep");
        }

        apiclient.connect();
        apiclient.reqContractDetails(contract2);

        try {
            Thread.sleep(1000);
        } catch (Exception e){
            System.err.println("Couldn't sleep");
        }

        apiclient.disconnect();
    }
}

按原样运行,有时会正确给出 conID: 8314conID: 8894 以及与上面相同的两个堆栈跟踪,但也会有时 em> 给 conID: 8314Connection Message: -1,507,Bad Message Length null错误消息 507 是:

错误的消息长度(仅限 Java) 指示从套接字读取时捕获到 EOF 异常。如果尝试使用已在使用的客户端 ID 连接到 TWS,或者如果 TWS 被锁定、关闭或断开连接,则可能会发生这种情况。它应该由客户端应用程序处理并用于指示套接字 连接无效。 IB Message Codes

不管怎样,两年来我一直对这个问题断断续续地感到非常沮丧。 (我不是专业的程序员。)我在网上搜索解决方案,甚至还请了一个程序员来帮助我,但都无济于事(虽然我在这个过程中学到了更多的 Java)。我还下载了最新版本的 IB API (v 9.76)。 IB API 的多个版本也会出现同样的问题。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。