写入NIO socketchannel会抛出IOException:资源暂时不可用

时间:2015-04-30 14:34:53

标签: java nio

我有一个NIO程序,可以监听两个IPC连接。 IPC基于UnixDomain套接字并使用jnr-unixdomainsocket库,它允许我用可选择的ServerSocketChannels和SocketChannel包装UDS。我使用这个库,因为我想用非阻塞IO运行程序,但阻止linux select调用。我写了一个名为NIODriver的类,它实现了通道接受和读取功能(下面的代码)。

我运行NIODriver类的两个实例(下面的代码),一个绑定到每个IPC管道。我的主类获取Java选择器的单个实例,并使用选择器注册NIODriver的ServerSocketChannel的两个实例。他们最初以Accept的兴趣注册。程序然后调用select并在那里等待。当外部程序连接时,主类获取与管道关联的NIODriver的实例并调用其acceptConnection方法。这将在其中创建SocketChannel实例,该实例在具有Read兴趣的同一选择器上注册。这两种情况都会发生这种情况,因为我有两个连接到每个管道的外部程序。

一个外部程序(让我们称之为A)连续地将数据(一个12字节的数据包)泵送到NIO程序。 select继续触发并调用NIODriver的channelRead方法读取数据,然后获取对另一个NIODriver实例的引用并调用其update()方法。更新方法将数据写入第二个外部程序(比如B)。当我在循环中运行它时,偶尔会出现IOException:资源暂时不可用。

下面的NIODriver类代码

公共课NIODriver {

int did;
String name;
String udsName;

UnixSocketAddress sockAddress;
UnixServerSocketChannel serverChannel;
Selector selector;
UnixSocketChannel channel;
ByteBuffer inbuf;
ByteBuffer outbuf;

int ctr = 0;

public NIODriver(int id, String name, String pipename) {
    this.did = id;
    this.name = name;
    this.udsName = pipename;

    this.sockAddress = new UnixSocketAddress(new File(udsName));
    inbuf = ByteBuffer.allocate(12*100);
    outbuf = ByteBuffer.allocate(12*100);
}

public void setSelector(Selector sel){
    this.selector = sel;
}

public boolean openConnection(){
    try {
        serverChannel = UnixServerSocketChannel.open();            
        serverChannel.configureBlocking(false);
        serverChannel.socket().bind(sockAddress);  
        serverChannel.register(selector, SelectionKey.OP_ACCEPT, this);
        return true;
    } catch (IOException ex) {
        Logger.getLogger(NIODriver.class.getName()).log(Level.SEVERE, null, ex);
        return false;
    }
}

public boolean acceptConnection(){
    try {
            System.out.println("accepting connection");                
            channel = serverChannel.accept();
            channel.configureBlocking(false);
            channel.register(selector, SelectionKey.OP_READ, this); 
            return true;
        } catch (IOException ex) {
            System.out.println("acceptConnection failed");
            ex.printStackTrace(System.out);
            return false;
        }
}

public int channelRead(){
    try {                
        int n = channel.read(inbuf); 
        if(n == -1)throw new DriverDisconnectedException("Channel.read returned -1");
        /* Important: Call flip before checking number of readable bytes */
        inbuf.flip();
        int num = inbuf.remaining();            
        if(num<12){
            /* Going to return since there is not enough bytes. Set buffer
                back to read mode before returning.
            */
            inbuf.compact();
            return 0;
        }

        int id = inbuf.getInt();            
        double dval = inbuf.getDouble();
    inbuf.compact();
    if(dval == 0){
    System.out.println("Read value="+dval); 
    }

    for(NIODriver obs: gt.observers){
        obs.update(id,dval);
    }                   

        return 0;
    } catch (IOException ex) {
        ex.printStackTrace(System.out);
        return 0;
    } catch (DriverDisconnectedException ex) {
        Logger.getLogger(NIODriver.class.getName()).log(Level.SEVERE, null, ex);
        return -1;
    } 
}


public void update(int id, double val){
    try {
        outbuf.putInt(id);
        outbuf.putDouble(val);
        outbuf.flip();
        channel.write(outbuf);
        outbuf.compact();
    } catch (IOException ex) {
        Logger.getLogger(NIODriver.class.getName()).log(Level.SEVERE, null, ex);
    } 
}

}

0 个答案:

没有答案