在服务器和本地进程之间创建通信流

时间:2012-11-13 15:58:38

标签: java scala

我一直在尝试创建一个本地进程,它将充当我的服务器的CLI。这个想法类似于DrushDrupal服务器的作用。

我还没有创建CLI界面(可能会使用第三方代码)但我想分享我的解决方案,以解决我在此问题上遇到的最大障碍:在本地进程之间将消息传输到运行和活动服务器而不使用REST服务,因为它们会增加某些命令的安全风险。

1 个答案:

答案 0 :(得分:0)

注意:此代码用Scala编写,但可以转换为Java

首先,我们需要创建一个扩展HttpServlet的servlet类。对于每个GET请求,servlet类将检查我们的线程(稍后解释)是否打开,如果没有尝试启动它。请注意,我们正在使用带有start方法的try catch,因为如果线程的状态是TERMINATED,则isAlive将返回true(我不知道为什么)。

如果servlet死掉,我也正在实现destroy方法来杀死我们的线程。我不确定如果servlet死了会运行线程会发生什么,但以防万一...

<强> Servlet.scala:

package com.example

import javax.servlet.http.HttpServlet
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse

class Servlet extends HttpServlet {

    override def doGet(req: HttpServletRequest, resp: HttpServletResponse) = {
        if (!CLIThread.isAlive) {
            try {
                CLIThread.start
            }
            catch {
                case _ => resp.getOutputStream().println("Error: thread state is, " + CLIThread.getState)
            }
        }
        resp.getOutputStream().println(CLIThread.pool)
    }

    override def destroy(): Unit = {
        super.destroy()
        CLIThread.shutdown
    }
}

我们的主题(CLIThread)是scala object扩展Thread类。

CLIThread有2种方法,pool&amp; shutdown,并将它们都传递给我们的Runnable实现。

CLIRunnable是传递给Thread构造函数的Runnable实现对象。

CLIRunnable有一个无效的ServerSocket(监听器),Socket(socket)&amp; InputStream(in),一个真正的布尔值(keepAlive)和一个空字符串(_pool)作为变量。

运行方法:

  1. 为侦听器变量分配新的ServerSocket。 我使用while循环,布尔值,try-catch块和随机函数来分配监听空端口的serverSocket,否则如果使用端口则会抛出异常
  2. 从侦听器对象分配接受的套接字(此方法保留线程,直到套接字连接到侦听器,这就是我们使用线程的原因)
  3. 将套接字输入流分配到
  4. 只要keepAlive为true,检查输入流是否为空,如果是,则用它填充_pool变量。
  5. 池方法:

    • 如果in变量不为null(CLIThread已启动并且套接字连接到我们的端口),则返回_pool String并将其清空。
    • 否则如果上述内容为false但侦听器不为null(尚未接受套接字),则打印出用户用于连接到我们端口的侦听器的值。
    • 如果上述所有方法都失败了,那么侦听器就会被取消,这意味着线程永远不会启动,我们打印字符串“listener == null ...”

    关机方法:

    1. 将keep alive设置为false(从while循环中释放线程)
    2. 如果侦听器不为null:
      1. 如果没有套接字连接到我们的端口,则创建一个连接并关闭它的新套接字,以便从它的循环中释放我们的监听器。
      2. 如果socket不为null,则关闭它。
      3. 关闭监听器
    3. <强> CLIThread.scala

      package com.example
      
      import java.io.InputStream
      import java.net.ServerSocket
      import java.net.Socket
      
      object CLIThread extends Thread(CLIRunner) {
          def pool: String = CLIRunner.pool
          def shutdown() = CLIRunner.shutdown()
      }
      
      protected final object CLIRunner extends Runnable {
          var listener: ServerSocket = null
          var socket: Socket = null
          var in: InputStream = null
          private var keepAlive = true
      
          private var _pool = ""
      
          def run: Unit = {
              var ok = false
              while (!ok) {
                  try {
                      listener = new ServerSocket((math.random * 10000).toInt)
                      ok = true;
                  }
                  catch {
                      case _ => {}
                  }
              }
              socket = listener.accept()
              in = socket.getInputStream
              while (keepAlive) {
                  while (in.available() > 0) _pool += in.read().toChar
              }
      
          }
          def pool: String = if (in != null) {
              val temp = _pool
              _pool = ""
              return temp
          }
          else if (listener != null) (listener.getInetAddress, listener.getLocalPort).toString
          else "listener == null..."
      
          def shutdown() {
              keepAlive = false
              if (listener != null) {
                  if (socket == null)
                      (new Socket(listener.getInetAddress, listener.getLocalPort)).close()
                  if (socket != null)
                      socket.close()
                  listener.close()
              }
          }
      }
      

      <强> CLI.scala

      package com.example
      
      import java.net.Socket
      import java.net.URL
      
      object CLI extends App {
          val addr = args(0) // The server address (example.com:8080)
      
          val addrUrl = new URL("http://" + addr + "/~cli/addr")
          var con = addrUrl.openConnection()
          var in = con.getInputStream()
          var cliAddr = ""
          while (in.available() > 0)
              cliAddr += in.read.toChar
      
          val portUrl = new URL("http://" + addr + "/~cli/port")
          con = portUrl.openConnection()
          in = con.getInputStream()
          var cliPort = ""
          while (in.available() > 0)
              cliPort += in.read.toChar
      
          val socket = new Socket(cliAddr, Integer.valueOf(cliPort))
      
          implicit def stringToByteArray(s: String) = s.toCharArray.map(c => c.toByte)
      
          socket.getOutputStream().write("Hellllo from CLI process")
      }
      

      <强> CliAddr.scala

      package org.sdms
      
      import javax.servlet.http.HttpServlet
      import javax.servlet.http.HttpServletRequest
      import javax.servlet.http.HttpServletResponse
      
      class CliAddr extends HttpServlet {
          override def doGet(req: HttpServletRequest, resp: HttpServletResponse) {
              resp.getWriter.print(CLIRunner.listener.getInetAddress.getHostAddress)
          }
      }
      

      <强> CliPort.scala

      package com.example
      
      import javax.servlet.http.HttpServlet
      import javax.servlet.http.HttpServletRequest
      import javax.servlet.http.HttpServletResponse
      
      class CliPort extends HttpServlet {
          override def doGet(req: HttpServletRequest, resp: HttpServletResponse) {
              resp.getWriter.print(CLIRunner.listener.getLocalPort)
          }
      }