Java Solaris NIO OP_CONNECT问题 [英] Java Solaris NIO OP_CONNECT problem
问题描述
我有一个Java客户端,该客户端使用使用Java NIO的TCP套接字连接到C ++服务器.这在Linux,AIX和HP/UX下有效,但在Solaris下OP_CONNECT
事件从不触发.
I have a Java client that connects to a C++ server using TCP Sockets using Java NIO. This works under Linux, AIX and HP/UX but under Solaris the OP_CONNECT
event never fires.
更多详细信息:
-
Selector.select()
返回0,并且所选键集"为空. - 该问题仅在连接到本地计算机(通过环回或以太网接口)时发生,但在连接到远程计算机时有效.
- 我已在两台不同的Solaris 10计算机上确认了该问题;使用两个JDK版本1.6.0_21和_26的物理SPARC和虚拟x64(VMWare).
Selector.select()
is returning 0, and the 'selected key set' is empty.- The issue only occurs when connecting to the local machine (via loopback or ethernet interface), but works when connecting to a remote machine.
- I have confirmed the issue under two different Solaris 10 machines; a physical SPARC and virtual x64 (VMWare) using both JDK versions 1.6.0_21 and _26.
以下是一些演示该问题的测试代码:
Here is some test code which demonstrates the issue:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class NioTest3
{
public static void main(String[] args)
{
int i, tcount = 1, open = 0;
String[] addr = args[0].split(":");
int port = Integer.parseInt(addr[1]);
if (args.length == 2)
tcount = Integer.parseInt(args[1]);
InetSocketAddress inetaddr = new InetSocketAddress(addr[0], port);
try
{
Selector selector = Selector.open();
SocketChannel channel;
for (i = 0; i < tcount; i++)
{
channel = SocketChannel.open();
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_CONNECT);
channel.connect(inetaddr);
}
open = tcount;
while (open > 0)
{
int selected = selector.select();
System.out.println("Selected=" + selected);
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext())
{
SelectionKey key = it.next();
it.remove();
channel = (SocketChannel)key.channel();
if (key.isConnectable())
{
System.out.println("isConnectable");
if (channel.finishConnect())
{
System.out.println(formatAddr(channel) + " connected");
key.interestOps(SelectionKey.OP_WRITE);
}
}
else if (key.isWritable())
{
System.out.println(formatAddr(channel) + " isWritable");
String message = formatAddr(channel) + " the quick brown fox jumps over the lazy dog";
ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
channel.write(buffer);
key.interestOps(SelectionKey.OP_READ);
}
else if (key.isReadable())
{
System.out.println(formatAddr(channel) + " isReadable");
ByteBuffer buffer = ByteBuffer.allocate(1024);
channel.read(buffer);
buffer.flip();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
String message = new String(bytes);
System.out.println(formatAddr(channel) + " read: '" + message + "'");
channel.close();
open--;
}
}
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
static String formatAddr(SocketChannel channel)
{
return Integer.toString(channel.socket().getLocalPort());
}
}
您可以使用命令行运行它:
You can run this using the command line:
java -cp . NioTest3 <ipaddr>:<port> <num-connections>
如果您要针对真实的回显服务运行,则端口应为7;即:
Where port should be 7 if you are running against a real echo service; i.e.:
java -cp . NioTest3 127.0.0.1:7 5
如果您无法运行真正的回显服务,则来源为此处一个>.在Solaris下使用以下命令编译回显服务器:
If you cannot get a real echo service running then the source to one is here. Compile the echo server under Solaris with:
$ cc -o echoserver echoserver.c -lsocket -lnsl
并像这样运行它:
$ ./echoserver 8007 > out 2>&1 &
这已作为 bug 报告给Sun.
This has been reported to Sun as a bug.
推荐答案
我使用以下方法解决了该错误:
I have worked-around this bug using the following:
如果Selector.select()
返回0(并且没有超时,如果使用了超时版本),则:
If Selector.select()
returns 0 (and didn't timeout, if the timeout version was used) then:
- 通过
selector.keys().iterator()
遍历在选择器中注册的键(记住不调用iterator.remove()
). - 如果已使用键设置了
OP_CONNECT
兴趣,则调用channel.finishConnect()
并执行isConnectable()
返回true
会执行的所有操作.
- Iterate over the keys registered with the selector via
selector.keys().iterator()
(remembering not to calliterator.remove()
). - If
OP_CONNECT
interest has been set with the key then callchannel.finishConnect()
and do whatever would have been done ifisConnectable()
has returnedtrue
.
例如:
if (selected == 0 && elapsed < timeout)
{
keyIter = selector.keys().iterator();
while (keyIter.hasNext())
{
key = keyIter.next();
if (key.isValid())
{
channel = (SocketChannel)key.channel();
if (channel != null)
{
if ((key.interestOps() & SelectionKey.OP_CONNECT) != 0)
{
if (channel.finishConnect())
{
key.interestOps(0);
}
}
}
}
}
}
这已作为 bug 报告给Sun.
This has been reported to Sun as a bug.
这篇关于Java Solaris NIO OP_CONNECT问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!