Tôi có một máy khách Java kết nối với máy chủ C++ bằng cách sử dụng TCP Sockets sử dụng Java NIO. Điều này làm việc dưới Linux, AIX và HP/UX nhưng dưới Solaris sự kiện OP_CONNECT
không bao giờ cháy.Vấn đề Java Solaris NIO OP_CONNECT
Thông tin chi tiết:
Selector.select()
được trở về 0, và 'chọn bộ chủ chốt' trống.- Sự cố chỉ xảy ra khi kết nối với máy cục bộ (qua giao diện loopback hoặc ethernet), nhưng hoạt động khi kết nối với máy từ xa.
- Tôi đã xác nhận sự cố trong hai máy Solaris 10 khác nhau; một SPARC vật lý và x64 ảo (VMWare) sử dụng cả hai phiên bản JDK 1.6.0_21 và _26.
Dưới đây là một số mã kiểm tra mà chứng tỏ vấn đề:
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());
}
}
Bạn có thể chạy này bằng cách sử dụng dòng lệnh:
java -cp . NioTest3 <ipaddr>:<port> <num-connections>
đâu cổng nên là 7 nếu bạn đang chạy chống lại một dịch vụ tiếng vọng thực; tức là:
java -cp . NioTest3 127.0.0.1:7 5
Nếu bạn không thể nhận được dịch vụ echo thực thì nguồn đó là here. Biên dịch máy chủ vang dưới Solaris với:
$ cc -o echoserver echoserver.c -lsocket -lnsl
và chạy nó như thế này:
$ ./echoserver 8007 > out 2>&1 &
này đã được báo cáo với Mặt Trời như một bug.
Có, kênh được đăng ký với 'Selector' ngay khi nó được mở và quan tâm đến' OP_CONNECT' được đặt sau khi lệnh gọi 'connect' (khác' ConnectionPendingException' được nâng lên). Chặn kết nối sẽ gây ra vấn đề cho tôi - các kết nối xảy ra vào thời điểm đặc biệt và nếu nó can thiệp vào I/O của các chủ đề khác thì điều đó thật tệ. – trojanfoe
@trojanfoe Kênh cần được đăng ký và được đặt thành OP_CONNECT trước khi kết nối(), nếu không bạn có thể bỏ lỡ sự kiện. ConnectPendingException không thể được ném * trước * bạn đã gọi là connect() - Tôi không hiểu. Lý do cho ngoại lệ đó khá rõ ràng trong Javadoc và đây không phải là nó. – EJP
Tôi đã thực hiện thay đổi đó và thử nghiệm nó dưới Linux (nó hoạt động) nhưng nó không khắc phục được vấn đề dưới Solaris. Tôi đã đề cập đến ngoại lệ sai - đó là NoConnectionPendingException nhưng điều đó không còn xảy ra vì vậy hãy bỏ qua điều đó. – trojanfoe