Java Solaris NIO OP_CONNECT问题 [英] Java Solaris NIO OP_CONNECT problem

查看:105
本文介绍了Java Solaris NIO OP_CONNECT问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个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:

  1. 通过selector.keys().iterator()遍历在选择器中注册的键(记住调用iterator.remove()).
  2. 如果已使用键设置了OP_CONNECT兴趣,则调用channel.finishConnect()并执行isConnectable()返回true会执行的所有操作.
  1. Iterate over the keys registered with the selector via selector.keys().iterator() (remembering not to call iterator.remove()).
  2. If OP_CONNECT interest has been set with the key then call channel.finishConnect() and do whatever would have been done if isConnectable() has returned true.

例如:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆