0

一段时间以来,我一直在尝试创建一个本地进程,该进程将充当我的服务器的 CLI。这个想法类似于Drush所做的Drupal服务器所做的。

我还没有创建 CLI 界面(可能会使用第 3 方代码),但我想分享我的解决方案以解决我在这件事上遇到的最大障碍:在不使用 REST 服务的情况下将本地进程之间的消息传输到我正在运行的服务器和活动服务器,因为他们通过一些命令增加了安全风险。

4

1 回答 1

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)是扩展Thread的scala 对象

CLIThread 有 2 个方法,pool 和 shutdown,它们都传递给我们的Runnable实现。

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

CLIRunnable 有一个空的 ServerSocket (listener)、Socket (socket) 和 InputStream (in)、一个真正的 Boolean (keepAlive) 和一个空的 String (_pool) 作为变量。

运行方法:

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

池方法:

  • 如果 in 变量不为空(CLIThread 已启动并且一个套接字连接到我们的端口),我们返回 _pool 字符串并将其清空。
  • 否则,如果上述情况为假,但侦听器不为空(尚未接受套接字),我们将打印出侦听器的值,供用户用于连接到我们的端口。
  • 如果以上所有方法都失败了,监听器为空,这意味着线程从未启动,我们打印字符串“listener == null ...”

关机方法:

  1. 将 keep alive 设置为 false(从 while 循环中释放线程)
  2. 如果监听器不为空:
    1. 如果没有套接字连接到我们的端口,则创建一个连接并关闭它的新套接字,以从它的循环中释放我们的侦听器。
    2. 如果套接字不为空,则关闭它。
    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)
    }
}
于 2012-11-13T15:58:37.727 回答