Java 带OSGi的套接字:捆绑已停止,套接字仍处于打开状态
在我的一个bundle中使用ServerSocket时,我面临着这个问题,我们把它称为:FooBundle 这个FooBundle还有一个SocketListener.java类。这个类是一个线程,为了对它做一点概述,我将粘贴一些伪代码:Java 带OSGi的套接字:捆绑已停止,套接字仍处于打开状态,java,sockets,osgi,Java,Sockets,Osgi,在我的一个bundle中使用ServerSocket时,我面临着这个问题,我们把它称为:FooBundle 这个FooBundle还有一个SocketListener.java类。这个类是一个线程,为了对它做一点概述,我将粘贴一些伪代码: public class SocketListener implements Runnable{ ServerSocket providerSocket; Socket connection = null; private boolean closeIt =
public class SocketListener implements Runnable{
ServerSocket providerSocket;
Socket connection = null;
private boolean closeIt = false;
public void run() {
try {
//Create the server socket
providerSocket = new ServerSocket(41000, 10);
} catch (IOException e1) {
//catching the exception....
}
while(!closeIt){
try{
connection = providerSocket.accept();
in = new Scanner(new InputStreamReader(onnection.getInputStream()));
while(in.hasNext() !=false)
message = message + " "+in.next();
// bla bla bla...
} catch (IOException e) {
//bla bla...
}
finally{
try{
if (message.equalsIgnoreCase("bye"))
providerSocket.close();
closeIt = true;
}
catch(IOException ioException){
//........
}
}
正如您所看到的,它是一个简单的线程,等待连接,直到它从一个SocketClient接收到的消息是bye
这就是我现在面临的问题:当捆绑包停止时,我确实需要重新启动整个OSGi框架:如果我尝试重新启动捆绑包,将抛出一条java.net.BindException消息:地址已在使用中。因此,我停止了捆绑,但插座尚未关闭
在OSGi中,您需要注意Activator中的stop方法必须包含哪些内容,但我无法将匿名线程的任何引用传递给Activator
假设这是捆绑包中的类图:
**FooBundle**
|__FooBundleActivator
|__FooImpl
|__SocketListener (thread)
SocketListener线程作为匿名线程从FooImpl类调用
我的问题是:在OSGi范式中,有没有合适的方法来控制匿名线程,特别是在我的例子中,控制非关闭套接字端口
提前感谢。在退出线程功能之前,无论消息如何,您都需要关闭侦听套接字。那么,对您来说真正有区别的是,在旧连接处于超时状态时,调用该套接字以允许绑定端口
并且,请在代码中使用更好的缩进技术…在退出线程函数之前,无论消息如何,您都需要关闭侦听套接字。那么,对您来说真正有区别的是,在旧连接处于超时状态时,调用该套接字以允许绑定端口
另外,请在代码中使用更好的缩进技术…在Activator外部实例化ServerSocket,并通过构造函数将其传递给SocketListener。您可以在激活器的stop函数中调用serverSocket.stop
如果调用ServerSocket.stop,将抛出SocketException,它是IOException的子类。请考虑在while迭代中处理IOException,这样它肯定会停止执行迭代。在激活器外部实例化ServerSocket,并通过构造函数将其传递给SocketListener。您可以在激活器的stop函数中调用serverSocket.stop
如果调用ServerSocket.stop,将抛出SocketException,它是IOException的子类。请考虑在while迭代中处理IOException,以确保它将停止执行迭代。如果您的包被告知停止,那么假设停止的人知道他在做什么。是的,你的协议期待着“再见”,但是狗屎发生了,任何与这些东西有问题的协议对于现实世界来说都太脆弱了。通常,OSGi中的所有任务都应该有一个生命周期。这就是我使用DS而不是激活器的代码
@Component
public class ProtocolServer extends Thread {
volatile ServerSocket server;
volatile Socket connection;
public ProtocolServer() {
super("Protocol Server on 4100"); // to identify the thread
}
@Activate void activate() {
setDaemon(true);
start();
}
@Deactivate void deactivate() {
interrupt();
// best effort close (even if null)
try { server.close(); } catch(Exception e) {}
try { connection.close(); } catch(Exception e) {}
join(10000); // waits 10 secs until thread exits
}
public void run() {
// loop for active component
while( !isInterrupted() )
try {
doServer();
} catch( Exception e) {
log(e);
// bad error, accept failed or bind failed
// or server socket was closed. If we should remain
// active, sleep to prevent overloading the
// system by trying too often, so sleep
if ( !isInterrupted() )
try { Thread.sleep(5000); } catch(Exception e) {}
}
}
private void doServer() throws Exception {
server = new ServerSocket(4100)
try {
while( !isInterrupted() )
doConnection(server);
} finally {
server.close();
}
}
private void doConnection(ServerSocket server) throws Exception {
connection = server.accept();
try {
doMessages(connection);
// the pseudo code exits here, but that seems
// kind of weird? If desired, interrupt
// this object, this will exit the thread
} catch( Exception e) {
log(e); // the connection failed, is not uncommon
} finally {
connection.close();
connection = null;
}
}
private void doMessages(Socket connection) {
MyScanner s = new MyScanner(socket);
String msg;
while( !isInterrupted() && !"bye".equals( msg=s.getMessage()))
process(msg);
}
}
OSGi中一个重要的设计考虑是,即使出现故障,组件也会继续工作。在网络中,经常会出现暂时性错误,这些错误会自行消失。即使他们不这样做,在您修复问题的同时,服务器继续尝试也是可取的。您的伪代码在实践中将是一场噩梦,因为它会在任何错误时消失。任何具有多个此类组件的系统都会很快变得不稳定
还有一件事让我感到惊讶,那就是您一次只支持一个连接。一般来说,最好不要对此进行限制,而是在自己的线程中处理消息。在这种情况下,您必须确保为连接创建的每个处理程序也被适当地关闭。如果您的包被告知停止,那么假设停止的人知道他在做什么。是的,你的协议期待着“再见”,但是狗屎发生了,任何与这些东西有问题的协议对于现实世界来说都太脆弱了。通常,OSGi中的所有任务都应该有一个生命周期。这就是我使用DS而不是激活器的代码
@Component
public class ProtocolServer extends Thread {
volatile ServerSocket server;
volatile Socket connection;
public ProtocolServer() {
super("Protocol Server on 4100"); // to identify the thread
}
@Activate void activate() {
setDaemon(true);
start();
}
@Deactivate void deactivate() {
interrupt();
// best effort close (even if null)
try { server.close(); } catch(Exception e) {}
try { connection.close(); } catch(Exception e) {}
join(10000); // waits 10 secs until thread exits
}
public void run() {
// loop for active component
while( !isInterrupted() )
try {
doServer();
} catch( Exception e) {
log(e);
// bad error, accept failed or bind failed
// or server socket was closed. If we should remain
// active, sleep to prevent overloading the
// system by trying too often, so sleep
if ( !isInterrupted() )
try { Thread.sleep(5000); } catch(Exception e) {}
}
}
private void doServer() throws Exception {
server = new ServerSocket(4100)
try {
while( !isInterrupted() )
doConnection(server);
} finally {
server.close();
}
}
private void doConnection(ServerSocket server) throws Exception {
connection = server.accept();
try {
doMessages(connection);
// the pseudo code exits here, but that seems
// kind of weird? If desired, interrupt
// this object, this will exit the thread
} catch( Exception e) {
log(e); // the connection failed, is not uncommon
} finally {
connection.close();
connection = null;
}
}
private void doMessages(Socket connection) {
MyScanner s = new MyScanner(socket);
String msg;
while( !isInterrupted() && !"bye".equals( msg=s.getMessage()))
process(msg);
}
}
OSGi中一个重要的设计考虑是,即使出现故障,组件也会继续工作。在网络中,经常会出现暂时性错误,这些错误会自行消失。即使他们不这样做,在您修复问题的同时,服务器继续尝试也是可取的。您的伪代码在实践中将是一场噩梦,因为它会在任何错误时消失。任何具有多个此类组件的系统都会很快变得不稳定
还有一件事让我感到惊讶,那就是您一次只支持一个连接。一般来说,最好不要对此进行限制,而是在自己的线程中处理消息。在这种情况下,您必须确保为连接创建的每个处理程序也相应地关闭
p> 谢谢你的回答,尼古拉。然而,将ReuseAddress参数设置为true并不能真正解决这个问题,因为我仍然得到相同的绑定异常。我的线程需要一直处于活动状态,直到消息bye到达,没有任何其他可能的情况,它必须继续运行。OSGi捆绑包的问题在于,您可以随时手动停止它们。如果停止此特定捆绑,则套接字不会自行关闭。哦,很抱歉缩进,只是手动编写了伪代码:S.+1以获取帮助您无法重新绑定同一套接字。您必须关闭它并创建一个新端口,或者停止对其调用accept,稍后再继续。问题是我无法创建一个新端口,因为我有许多客户端正在转发到此特定端口。现在的解决方案是停止整个OSGi框架,这对我的应用程序来说不是很好。应该有任何类型的方法来控制匿名线程在捆绑包中的行为,但是我找不到合适的解决方案。我不熟悉这个框架。在开始/停止事件时,是否有来自it的任何挂钩/回调?我认为您需要重写一些函数,在这些函数中您可以创建/关闭套接字。注意,这些可能在不同的线程上。你是对的,套接字不会自动关闭。你认为OSGi会为你免费处理这件事吗??在bundle的start方法中创建的任何内容都必须在stop方法中清除。这包括您打开的任何套接字、启动的任何线程等。这是您作为捆绑包作者的责任,而不是其他任何人的责任。如果你需要重组你的代码使之成为可能,那就这样吧。谢谢你的回答Nikolai。然而,将ReuseAddress参数设置为true并不能真正解决这个问题,因为我仍然得到相同的绑定异常。我的线程需要一直处于活动状态,直到消息bye到达,没有任何其他可能的情况,它必须继续运行。OSGi捆绑包的问题在于,您可以随时手动停止它们。如果停止此特定捆绑,则套接字不会自行关闭。哦,很抱歉缩进,只是手动编写了伪代码:S.+1以获取帮助您无法重新绑定同一套接字。您必须关闭它并创建一个新端口,或者停止对其调用accept,稍后再继续。问题是我无法创建一个新端口,因为我有许多客户端正在转发到此特定端口。现在的解决方案是停止整个OSGi框架,这对我的应用程序来说不是很好。应该有任何类型的方法来控制匿名线程在捆绑包中的行为,但是我找不到合适的解决方案。我不熟悉这个框架。在开始/停止事件时,是否有来自it的任何挂钩/回调?我认为您需要重写一些函数,在这些函数中您可以创建/关闭套接字。注意,这些可能在不同的线程上。你是对的,套接字不会自动关闭。你认为OSGi会为你免费处理这件事吗??在bundle的start方法中创建的任何内容都必须在stop方法中清除。这包括您打开的任何套接字、启动的任何线程等。这是您作为捆绑包作者的责任,而不是其他任何人的责任。如果你需要重新构造你的代码使之成为可能,那么就这样吧。谢谢你的回答。我在使用您的方法时面临的唯一问题是,我已经过多地重载了activator,因此我不想再在其中编写代码。启动和停止方法应简单,以避免捆绑激活过程中的任何延迟。无论如何,你给了我一个未来部署的好主意+1在这种情况下,您必须以某种方式将启动和停止逻辑与函数和类分开。但是,如果创建新类,它们还必须具有停止/关闭功能。无论如何,唯一的解决方案是当捆绑包停止时,您能够停止服务器套接字。感谢您的回答。我在使用您的方法时面临的唯一问题是,我已经过多地重载了activator,因此我不想再在其中编写代码。启动和停止方法应简单,以避免捆绑激活过程中的任何延迟。无论如何,你给了我一个未来部署的好主意+1在这种情况下,您必须以某种方式将启动和停止逻辑与函数和类分开。但是,如果创建新类,它们还必须具有停止/关闭功能。无论如何,唯一的解决方案是在捆绑包停止时停止服务器套接字。关于只接收一个客户端的问题是因为伪代码,我的真实代码接受多个连接。彼得,非常感谢你的回答。不仅是为了规范,也是为了建议。收到Peter Kriens的答复真的很荣幸。谢谢只接收一个客户端的问题是因为伪代码,我的真实代码接受多个连接。彼得,非常感谢你的回答。 不仅是为了规范,也是为了建议。收到Peter Kriens的答复真的很荣幸。谢谢