Java 写入NIO socketchannel引发IOException:资源暂时不可用
我有一个NIO程序,它监听两个IPC连接。IPC基于UnixDomain套接字并使用jnr unixdomainsocket库,该库允许我使用可选的ServerSocketChannels和SocketChannels包装UDS。我之所以使用这个库,是因为我想用非阻塞IO运行程序,但在linux select调用上阻塞。我编写了一个名为NIODriver的类,它实现了通道接受和读取函数(代码如下)Java 写入NIO socketchannel引发IOException:资源暂时不可用,java,nio,Java,Nio,我有一个NIO程序,它监听两个IPC连接。IPC基于UnixDomain套接字并使用jnr unixdomainsocket库,该库允许我使用可选的ServerSocketChannels和SocketChannels包装UDS。我之所以使用这个库,是因为我想用非阻塞IO运行程序,但在linux select调用上阻塞。我编写了一个名为NIODriver的类,它实现了通道接受和读取函数(代码如下)Iam运行两个NIODriver类实例(下面的代码),每个IPC管道绑定一个实例。我的主类获得Jav
Iam运行两个NIODriver类实例(下面的代码),每个IPC管道绑定一个实例。我的主类获得Java选择器的一个实例,并向选择器注册NIODriver的ServerSocketChannel的两个实例。他们最初是以接受利息登记的。然后程序调用select并在那里等待。当外部程序连接时,main类获取与管道关联的NIODriver实例并调用其acceptConnection方法。这将在其内部创建SocketChannel实例,该实例在具有读取兴趣的同一选择器上注册。这两种情况都会发生,因为我有两个外部程序,一个连接到每个管道。
一个外部程序(我们称之为A)连续向NIO程序泵送数据(一个12字节的数据包)。select会不断触发并调用NIODriver的channelRead方法,该方法读取数据,然后获取对另一个NIODriver实例的引用并调用其update()方法。update方法将数据写入第二个外部程序(比如B)。当我在循环中运行它时,偶尔会得到IOException:resource暂时不可用。
下面是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);
}
}
int-did;
字符串名;
字符串udsName;
UnixSocketAddress sockAddress;
unixserversocketchannelserverchannel;
选择器;
UnixSocketChannel通道;
ByteBuffer inbuf;
比特布弗爆发;
int ctr=0;
公共NIODriver(int-id、字符串名称、字符串管道名称){
this.did=id;
this.name=名称;
this.udsName=管道名称;
this.sockAddress=newunixsocketAddress(新文件(udsName));
inbuf=字节缓冲分配(12*100);
exputf=字节缓冲分配(12*100);
}
公共选择器(选择器sel){
this.selector=sel;
}
公共布尔openConnection(){
试一试{
serverChannel=UnixServerSocketChannel.open();
serverChannel.configureBlocking(false);
serverChannel.socket().bind(sockAddress);
serverChannel.register(选择器,SelectionKey.OP_ACCEPT,this);
返回true;
}捕获(IOEX异常){
Logger.getLogger(NIODriver.class.getName()).log(Level.SEVERE,null,ex);
返回false;
}
}
公共布尔接受连接(){
试一试{
System.out.println(“接受连接”);
channel=serverChannel.accept();
信道配置阻塞(假);
通道寄存器(选择器,SelectionKey.OP_READ,this);
返回true;
}捕获(IOEX异常){
System.out.println(“acceptConnection失败”);
例如printStackTrace(系统输出);
返回false;
}
}
公共int channelRead(){
试试{
int n=信道读取(inbuf);
如果(n==-1)抛出新的DriverDisconnectedException(“Channel.read返回-1”);
/*重要提示:在检查可读字节数之前调用flip*/
inbuf.flip();
int num=inbuf.remaining();
如果(NUMCA)您可以发布框架代码,以更清楚地演示事件序列?以及堆栈跟踪?并编辑您的问题以删除不正确的部分吗?感谢您的关注Neil和EJP。对于我的长时间延迟表示歉意。我已经完全重写了问题。请审阅。