我有一个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);
}
}
}