我的服务器正在监听2个端口,并且它应该同时在每个端口上执行单独的功能。
我的问题是,服务器阻塞,直到第一个端口的客户端首先连接。
例如:如果第二个客户端在连接到第一个端口之前尝试连接到第二个端口,它将不允许它连接。
我创建了2个扩展到线程类的类,因此它们应并行等待任何客户端,而不是阻塞其后的内容。 但这似乎不像我期望的那样。
public static void main(String[] args) throws Exception {
System.out.println("server is running.");
int clientNumber = 0;
ServerSocket listenerTrans = new ServerSocket(9899);
ServerSocket listenerDeter = new ServerSocket(9898);
try {
while (true) {
new Deteriment(listenerDeter.accept(), clientNumber++).start();
new Transpose(listenerTrans.accept(), clientNumber++).start();
}
} finally {
listenerTrans.close();
listenerDeter.close();
}
}
Deteriment和Transpose是我的扩展到线程类的类。
我希望listenerDeter.accept()不会阻止listenerTrans.accept(),我希望两个线程的accept()并行发生。 还有为什么它在我的代码中不是并行发生的?
答案 0 :(得分:1)
答案是使用ServerSocketChannel
和Selector
。 Selector
允许您的应用程序使用单个线程在多个通道上复用I / O。可以在时钟或非阻塞模式下使用
以下是一个示例(从How java nio ServerSocketChannel accept works?借来并根据您的用例进行了修改):
// Create the 2 server socket channels
ServerSocketChannel server1 = ServerSocketChannel.open();
ServerSocketChannel server2 = ServerSocketChannel.open();
// Configure channels for nonblocking I/O
server1.configureBlocking(false);
server2.configureBlocking(false);
// Bind channels' IP and port
server1.socket().bind(new java.net.InetSocketAddress(host, 9899));
server2.socket().bind(new java.net.InetSocketAddress(host, 9898));
// Create the selector
Selector selector = Selector.open();
// Register channels to selector (type OP_ACCEPT)
SelectionKey key1 = server1.register(selector, SelectionKey.OP_ACCEPT);
SelectionKey key2 = server2.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
selector.select(); // blocks until one or more of the registered channels
// has actionable I/O
Iterator it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey selKey = (SelectionKey) it.next();
if (selKey.isAcceptable()) {
ServerSocketChannel ssc = (ServerSocketChannel) selKey.channel();
SocketChannel sc = ssc.accept();
if (selKey.equals(key1)) {
new Deteriment(sc.socket() ...).start();
} else {
new Transpose(sc.socket(), ...).start();
}
}
}
}
(注意事项:1:未测试,2:可能更优雅,3:可能发生资源泄漏,4:您确实应该使用线程池/执行程序,而不是手动触发新线程)
答案 1 :(得分:0)
因此,首先,如果您希望它异步,则需要为您声明的每个ServerSocket使用单独的线程。为什么?由于概念java.net阻碍了处理网络思维的不可扩展方式。如果您希望它具有更高的可扩展性,但又不那么抽象(我的意思是您将分配缓冲区^ ^),那么您应该寻找java nio。 **编辑:** 我稍微修改一下代码,它应该可以完成工作,但是它的改进是我的意思,不是最高级的版本^ ^
public static void main(String[] args) throws Exception {
System.out.println("server is running.");
final int[] clientNumber = {0};
ServerSocket listenerTrans = new ServerSocket(9899);
ServerSocket listenerDeter = new ServerSocket(9898);
try {
ExecutorService ex = Executors
.newFixedThreadPool(2);
ex.execute(
() -> {
try {
Socket s = listenerDeter.accept();
new Deteriment(s, clientNumber[0]++).start();
} catch (IOException e) {
e.printStackTrace();
}
}
);
ex.execute(
() -> {
try {
Socket s = listenerDeter.accept();
new Transpose(s, clientNumber[0]++).start();
} catch (IOException e) {
e.printStackTrace();
}
}
);
} finally {
//listenerTrans.close();
//listenerDeter.close();
}
}