0

私はしばらくの間、サーバーのCLIとして機能するローカルプロセスを作成しようとしてきました。この考え方は、DrushDrupalサーバーに対して行うことと似ています。

私はまだCLIインターフェイスを作成していません(おそらくサードパーティのコードを使用します)が、問題の最大の障害に対するソリューションを共有したいと思いました:RESTサービスを使用せずにローカルプロセス間で実行中のサーバーとアクティブなサーバーにメッセージを転送する一部のコマンドでセキュリティリスクが追加されます。

4

1 に答える 1

0

注:このコードはScalaで書かれていますが、Javaに変換できます

まず、HttpServletを拡張するサーブレットクラスを作成する必要があります。サーブレットクラスは、GETリクエストごとに、スレッド(後で説明)が開いているかどうかを確認し、開いていない場合は起動を試みます。スレッドの状態がTERMINATEDの場合、 isAliveはtrueを返すため(理由はわかりません)、startメソッドでtrycatchを使用していることに注意してください。

また、サーブレットが停止した場合にスレッドを強制終了するためのdestroyメソッドを実装しています。サーブレットが停止した場合に実行中のスレッドがどうなるかはわかりませんが、念のため...

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にはpoolとshutdownの2つのメソッドがあり、どちらもRunnable実装に渡されます。

CLIRunnableは、Threadコンストラクターに渡されるRunnable実装オブジェクトです。

CLIRunnableには、変数としてnullのServerSocket(リスナー)、Socket(ソケット)、InputStream(in)、真のブール値(keepAlive)、および空の文字列(_pool)があります。

runメソッド:

  1. 新しいServerSocketをリスナー変数に割り当てます。whileループ、ブール値、try-catchブロック、およびランダム関数を使用して、空のポートをリッスンするserverSocketを割り当てます。そうしないと、ポートが使用された場合に例外がスローされます。
  2. リスナーオブジェクトから受け入れられたソケットを割り当てます(このメソッドは、ソケットがリスナーに接続するまでスレッドを保持します。そのため、スレッドを使用します)
  3. ソケット入力ストリームをに割り当てます
  4. keepAliveがtrueである限り、入力ストリームが空でないかどうかをチェックし、空である場合は_pool変数を空にします。

プール方式:

  • in変数がnullでない場合(CLIThreadが開始され、ソケットがポートに接続されている場合)、_pool文字列を返し、空にします。
  • それ以外の場合、上記がfalseであるが、リスナーがnullでない場合(ソケットはまだ受け入れられていません)、ユーザーがポートへの接続に使用するリスナーの値を出力します。
  • 上記のすべてが失敗し、listenerがnullになる場合、つまりスレッドが開始されなかった場合は、文字列 "listener ==null..."を出力します。

シャットダウン方法:

  1. keep aliveをfalseに設定します(whileループからスレッドを解放します)
  2. リスナーがnullでない場合:
    1. ポートに接続されているソケットがない場合は、接続して閉じる新しいソケットを作成し、リスナーをループから解放します。
    2. ソケットがnullでない場合は、ソケットを閉じます。
    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 に答える