1

我在使用ServerSocket其中一个捆绑包时遇到了这个问题,我们称之为:FooBundle

这个FooBundle有一个SocketListener.java类。这个类是一个线程,为了对它做一个简单的概述,我将粘贴一些伪代码:

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"

这是我现在面临的问题:当 Bundle停止时,我确实需要重新启动整个OSGi 框架:如果我尝试重新启动包,java.net.BindException则会抛出一条消息:“地址已在使用中”。所以,我停止了捆绑,但套接字还没有关闭。

在 OSGi 中,您需要注意必须包含的stop()方法中的内容Activator,但我无法将匿名线程的任何引用传递给 Activator。

想象一下,这是我在包中的类图:

**FooBundle**
|__FooBundleActivator
|__FooImpl
|__SocketListener (thread)

该线程作为匿名线程SocketListener从类中调用。FooImpl

我的问题是:在 OSGi 范式中,是否有任何适当的方法可以控制匿名线程,特别是在我的情况下,控制非关闭套接字端口?

提前致谢。

4

3 回答 3

4

如果你的包裹被告知停止,那么假设停止的人知道他在做什么。是的,您的协议期待“再见”,但糟糕的事情发生了,任何有这些问题的协议对于现实世界来说都太脆弱了。一般来说,你在 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 中的一个重要设计考虑因素是,即使出现故障,组件也能继续工作。在网络中,您经常会遇到自行消失的暂时性错误。即使他们不这样做,也希望服务器在您解决问题时继续尝试。您的伪代码在实践中将是一场噩梦,因为它会在任何错误时消失。任何具有多个此类组件的系统都会很快变得不稳定。

让我感到惊讶的一件事是您一次只支持一个连接。一般来说,最好不要限制这一点并在他们自己的线程中处理消息。在这种情况下,您必须确保为连接创建的每个处理程序也正确关闭。

于 2013-05-22T07:37:53.013 回答
2

在外部(可能在 Activator 中)实例化 ServerSocket 并通过构造函数将其传递给 SocketListener。您可以在 Activator 的停止函数中调用 serverSocket.stop() 比。

如果您调用 ServerSocket.stop(),则会抛出 SocketException,它是 IOException 的子类。请考虑在 while 迭代中处理 IOException 的方式,它肯定会停止执行迭代。

于 2013-05-21T16:42:38.523 回答
1

在退出线程函数之前,无论消息如何,您都需要关闭该侦听套接字。那么真正对您产生影响的是调用setReuseAddress(true)该套接字以允许绑定端口,而旧连接在超时状态下挂起。

并且,请在您的代码中使用更好的缩进技术......

于 2013-05-21T15:55:32.683 回答