Break infinite loop java program using PHP exec command - java

I have JDK and I am trying to execute Main.java program which contains infinite loop and I want to break java Main.java < input.txt > output.txt command if it goes into infinite loop and if not infinite loop than dont won't to break program.. Any solution ?? In trouble
<?php
exec('cmd /k c:/wamp/www/javac Main.java 2>&1', $outputAndErrors, $return_value);
for($i=0 ; $i<sizeof($outputAndErrors) ; $i++)
{
$output1=htmlspecialchars($outputAndErrors[$i],ENT_QUOTES);
echo "$output1";
$flag=1;
}
if(!$flag)
{
exec('cmd /k c:/wamp/www/java Main.java < input.txt > output.txt', $outputAndErrors, $return_value);
//want to give timeout but if exec goes to infinite loop than below statement will not executed
}
?>

Try wrapping it in a class like this (essentially wrapping it in nohup COMMAND > /dev/null 2>&1 & echo $! to get the pid and work with it that way in the background)
<?php
// You may use status(), start(), and stop(). notice that start() method gets called automatically one time.
$process = new Process('ls -al');
// or if you got the pid, however here only the status() metod will work.
$process = new Process();
$process.setPid(my_pid);
?>
<?php
// Then you can start/stop/ check status of the job.
$process.stop();
$process.start();
if ($process.status()){
echo "The process is currently running";
}else{
echo "The process is not running.";
}
?>
<?php
/* An easy way to keep in track of external processes.
* Ever wanted to execute a process in php, but you still wanted to have somewhat controll of the process ? Well.. This is a way of doing it.
* #compability: Linux only. (Windows does not work).
* #author: Peec
*/
class Process{
private $pid;
private $command;
public function __construct($cl=false){
if ($cl != false){
$this->command = $cl;
$this->runCom();
}
}
private function runCom(){
$command = 'nohup '.$this->command.' > /dev/null 2>&1 & echo $!';
exec($command ,$op);
$this->pid = (int)$op[0];
}
public function setPid($pid){
$this->pid = $pid;
}
public function getPid(){
return $this->pid;
}
public function status(){
$command = 'ps -p '.$this->pid;
exec($command,$op);
if (!isset($op[1]))return false;
else return true;
}
public function start(){
if ($this->command != '')$this->runCom();
else return true;
}
public function stop(){
$command = 'kill '.$this->pid;
exec($command);
if ($this->status() == false)return true;
else return false;
}
}
?>

This is only a suggestion. There will be better answer for your question.
Inside the java infinity loop check some value from other text file. Its like
while true {
v = readFile('your_txt_file.txt')
if v == "true" {
break;
}
//do your stuff }
If you can set your_txt_file.txt value to false of what ever except true then java loop will be break.

You need to open a port to listen to in java, and then connect and send something to that port from php.
Check out #TomaszNurkiewicz answer here where he says
"""
What you probably want is to create a ServerSocket and listen on it:
ServerSocket serverSocket = new ServerSocket(4000);
Socket socket = serverSocket.accept();
The second line will block until some other piece of software connects to your machine on port 4000. Then you can read from the returned socket. Look at this tutorial, this is actually a very broad topic (threading, protocols...)
"""
and for opening up the socket with php you can use the code (or somethign close to it) provided here by #sanmi from the manual
"""
<?php
error_reporting(E_ALL);
/* Get the port for the WWW service. */
$service_port = getservbyname('www', 'tcp');
/* Get the IP address for the target host. */
$address = gethostbyname('www.example.com');
/* Create a TCP/IP socket. */
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
echo "socket_create() failed: reason: " .
socket_strerror(socket_last_error()) . "\n";
}
echo "Attempting to connect to '$address' on port '$service_port'...";
$result = socket_connect($socket, $address, $service_port);
if ($result === false) {
echo "socket_connect() failed.\nReason: ($result) " .
socket_strerror(socket_last_error($socket)) . "\n";
}
$in = "HEAD / HTTP/1.1\r\n";
$in .= "Host: www.example.com\r\n";
$in .= "Connection: Close\r\n\r\n";
$out = '';
echo "Sending HTTP HEAD request...";
socket_write($socket, $in, strlen($in));
echo "OK.\n";
echo "Reading response:\n\n";
while ($out = socket_read($socket, 2048)) {
echo $out;
}
socket_close($socket);
?>
"""

Related

Create external process and wait 5 seconds kill it in php

I want to kill a external process after 5 seconds it created
That process is javac Hello.java & java Hello
I figured out a method that is kill process's pid, but samples below cannot get pid.
<?php
system('javac Hello.java & java Hello', $retval);
popen('javac Hello.java & java Hello', 'w');
?>
I don't understand proc_open() and proc_get_status example in PHP manual.
In my case, how to do that?
Here is a very clear explanation for how to use proc_open()
https://www.sitepoint.com/proc-open-communicate-with-the-outside-world/
I've done my job for creating an external process to compile , run java program, wait seconds, kill java running process in PHP script.
Here is that script:
<?php
/**
This is a judge script for verifying lab assignment
of NTU Civil Engineering Computer Programing with no testdata.
You can copy, redistribute, or modify it freely.
Tips:
It is not necessary to use file already provided.
Any related file can be uploaded via testdata field.
Then how to apply specific file uploaded to ./problem/testdata/[item]/[subitem]
completely depends on by how the judge file is defined.
*/
// Error report mechanism of this script
ini_set('display_errors', '1');
ERROR_REPORTING(E_ALL);
// Auto load class definition file that this script will be using.
function __autoload($class_name) {
include_once($class_name . '.php');
}
class Java_No_Input {
private $stu_account;
private $item;
private $subitem;
private $main;
private $dir_name;
private $status;
private $solution_output;
private $student_output;
private $hookup;
public function __construct () {
// Arguments: student account, item, subitem
$this->stu_account = $_SERVER['argv'][1];
$this->item = $_SERVER['argv'][2];
$this->subitem = $_SERVER['argv'][3];
try {
// Connect to MySQL database TAFreeDB
$this->hookup = UniversalConnect::doConnect();
// Create directory to put source codes temporarily
$this->createDir();
// Fetch student and solution source from table [item]_[subitem]
$this->fetchSource();
// Start judge
$this->startJudge();
// Update judge status
$this->updateStatus();
// Remove directory
$this->removeDir();
$this->hookup = null;
exit();
}
catch (PDOException $e) {
echo 'Error: ' . $e->getMessage() . '<br>';
}
}
public function createDir () {
$this->dir_name = './process/' . uniqid(time(), true);
mkdir($this->dir_name);
mkdir($this->dir_name . '/student');
mkdir($this->dir_name . '/solution');
}
public function removeDir () {
system('rm -rf ' . $this->dir_name, $retval);
if ($retval !== 0 ) {
echo 'Directory can not be removed...';
exit();
}
}
public function fetchSource () {
$stmt = $this->hookup->prepare('SELECT main, classname, original_source, ' . $this->stu_account . ' FROM ' . $this->item . '_' . $this->subitem);
$stmt->execute();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
if ($row['main'] === 'V') {
$this->main = $row['classname'];
}
$student = fopen($this->dir_name . '/student/' . $row['classname'], 'w');
fwrite($student, $row[$this->stu_account]);
fclose($student);
$solution = fopen($this->dir_name . '/solution/' . $row['classname'], 'w');
fwrite($solution, $row['original_source']);
fclose($solution);
}
}
public function startJudge () {
// Solution and student directory whose source is in
$solution_dir = $this->dir_name . '/solution';
$student_dir = $this->dir_name . '/student';
// Compile source code from both solution and student
$solution_CE = $this->compile($solution_dir);
if (!empty($solution_CE)) {
// Configure result that will response to client side
$error_msg = '<h1>Solution has compiler error</h1>' . '<pre><code>' . $solution_CE . '</code></pre>';
$this->configureView($error_msg);
// System error
$this->status = 'SE';
return;
}
$student_CE = $this->compile($student_dir);
if (!empty($student_CE)) {
// Configure result that will response to client side
$error_msg = '<h1>Your source code has compiler error</h1>' . '<pre><code>' . $student_CE . '</code></pre>';
$this->configureView($error_msg);
// Compiler error
$this->status = 'CE';
return;
}
// Execute source code from both solution and student
$solution_RE = $this->execute($solution_dir, 2);
if (!empty($solution_RE)) {
// Configure result that will response to client side
$error_msg = '<h1>Solution has runtime error</h1>' . '<pre><code>' . $solution_RE . '</code></pre>';
$this->configureView($error_msg);
// System error
$this->status = 'SE';
return;
}
$student_RE = $this->execute($student_dir, 2);
if (!empty($student_RE)) {
// Configure result that will response to client side
$error_msg = '<h1>Your source code has runtime error</h1>' . '<pre><code>' . $student_RE . '</code></pre>';
$this->configureView($error_msg);
// Runtime error
$this->status = 'RE';
return;
}
// Compare output from both solution and student
$this->solution_output = $this->execute($solution_dir, 1);
$this->student_output = $this->execute($student_dir, 1);
$retval = strcmp($this->solution_output, $this->student_output);
if ($retval === 0) {
// Accept
$this->status = 'AC';
}
else {
// Wrong Answer
$this->status = 'WA';
}
// Configure result that will response to client side
$error_msg = null;
$this->configureView($error_msg);
return;
}
public function compile ($dir) {
// Configure descriptor array
$desc = array (
0 => array ('pipe', 'r'), // STDIN for process
1 => array ('pipe', 'w'), // STDOUT for process
2 => array ('pipe', 'w') // STDERR for process
);
// Configure compilation command
$cmd = 'javac -d ' . $dir . ' ';
$source = glob($dir . '/*');
foreach ($source as $key => $value) {
$cmd .= $value . ' ';
}
// Create compilation process
$process = proc_open($cmd, $desc, $pipes);
// Close STDIN pipe
fclose($pipes[0]);
// Get output of STDERR pipe
$error = stream_get_contents($pipes[2]);
// Close STDOUT and STDERR pipe
fclose($pipes[1]);
fclose($pipes[2]);
// Close process
proc_close($process);
return $error;
}
public function execute ($dir, $pipe_id) {
// Configure descriptor array
$desc = array (
0 => array ('pipe', 'r'), // STDIN for process
1 => array ('pipe', 'w'), // STDOUT for process
2 => array ('pipe', 'w') // STDERR for process
);
// Configure execution command
$cmd = 'exec java -classpath ' . $dir . ' ';
$last_pos = strrpos($this->main, '.java');
$classname = substr($this->main, 0, $last_pos);
$cmd .= $classname;
// Create execution process
$process = proc_open($cmd, $desc, $pipes);
// Get pid of execution process
$process_status = proc_get_status($process);
$pid = $process_status['pid'];
// Close STDIN pipe
fclose($pipes[0]);
// Wait seconds
sleep(1);
// Kill execution process
posix_kill($pid, SIGTERM);
// Get output of STDOUT or STDERR pipe
$output = stream_get_contents($pipes[$pipe_id]);
// Close STDOUT and STDERR pipe
fclose($pipes[1]);
fclose($pipes[2]);
return $output;
}
public function updateStatus () {
$stmt = $this->hookup->prepare('UPDATE ' . $this->item . ' SET ' . $this->stu_account . '=\'' . $this->status . '\' WHERE subitem=\'' . $this->subitem . '\'');
$stmt->execute();
}
public function configureView ($error_msg) {
if (!is_null($error_msg)) {
echo $error_msg;
}
else {
$result = '';
if ($this->status === 'WA') {
$result = 'Wrong Answer';
}
if ($this->status === 'AC') {
$result = 'Accept';
}
echo<<<EOF
<h1>$result</h1>
<div class='WHOSE_DIV'>
<img class='UP_DOWN_IMG' src='./tafree-svg/attention.svg'>
<div class='RES_DIV'>
<div class='SOL_DIV'>{$this->solution_output}</div>
<div class='STU_DIV'>{$this->student_output}</div>
</div>
</div>
EOF;
}
return;
}
}
$judger = new Java_No_Input();
?>

core php: My php script does not accept any request until current request is complete

I have a php script:
<?php
header('Content-type: text/plain');
require_once( explode( "wp-content" , __FILE__ )[0] . "wp-load.php" );
require_once("user_details.php");
$GLOBALS['woocommerce'] = WC();
getPostData($woocommerce);
function getPostData($woocommerce){
$user_id;
if(isset($_GET['userName'], $_GET['password'])){
$user = wp_authenticate($_GET['userName'], $_GET['password']);
if (!is_wp_error($user)){
if(filter_var($_GET['userName'], FILTER_VALIDATE_EMAIL)) {
$user_id=getUserByEmail($_GET['userName']);
}
else {
$user_id=getUserByUserName($_GET['userName']);
}
$user_info=getUserInfo($user_id);
$user_info= json_encode(array($user_info));
echo $user_info;
}
else{
$error = $user->get_error_message();
echo '{"RESULT":"ERROR_INVALID_LOGIN_DETAILS"}';
}
}
else{
echo '{"RESULT":"_GET_ERROR"}';
}
}
?>
I am unable to call this script from multiple android/ios devices.. only the first request is handled while others wait in queue forever... someone please help me how to handle this!

Getting output from Perl script called from Java code

I've read a lot of questions/examples on this issue, but unfortunately I have not been able to solve my problem. I need to call a Perl script (that I cannot change) from Java code, and then I need to get the output from that script.
The script is used to take student programming homework assignments, and check them for copying by comparing all of them together. The script can take ~45 seconds to run, but only requires the arguments to be properly formatted, there is no interactivity.
My issue is when I call the script from my Java code I get the first line of output from the script but nothing else. I'm using Runtime.exe() and then waitFor() to wait for the script to finish. However the waitFor() function returns before the script actually finishes. I don't know any Perl so I'm not sure if the script is doing something that 'confuses' the java Process object, or if there's an issue in my code.
Process run = Runtime.getRuntime().exec(cmd);
output = new BufferedReader(new InputStreamReader(run.getInputStream()));
run.waitFor();
String temp;
while((temp = output.readLine()) != null){
System.out.println(temp);
}
The Perl script..
use IO::Socket;
#
# As of the date this script was written, the following languages were supported. This script will work with
# languages added later however. Check the moss website for the full list of supported languages.
#
#languages = ("c", "cc", "java", "ml", "pascal", "ada", "lisp", "scheme", "haskell", "fortran", "ascii", "vhdl", "perl", "matlab", "python", "mips", "prolog", "spice", "vb", "csharp", "modula2", "a8086", "javascript", "plsql", "verilog");
$server = 'moss.stanford.edu';
$port = '7690';
$noreq = "Request not sent.";
$usage = "usage: moss [-x] [-l language] [-d] [-b basefile1] ... [-b basefilen] [-m #] [-c \"string\"] file1 file2 file3 ...";
#
# The userid is used to authenticate your queries to the server; don't change it!
#
$userid=[REDACTED];
#
# Process the command line options. This is done in a non-standard
# way to allow multiple -b's.
#
$opt_l = "c"; # default language is c
$opt_m = 10;
$opt_d = 0;
$opt_x = 0;
$opt_c = "";
$opt_n = 250;
$bindex = 0; # this becomes non-zero if we have any base files
while (#ARGV && ($_ = $ARGV[0]) =~ /^-(.)(.*)/) {
($first,$rest) = ($1,$2);
shift(#ARGV);
if ($first eq "d") {
$opt_d = 1;
next;
}
if ($first eq "b") {
if($rest eq '') {
die "No argument for option -b.\n" unless #ARGV;
$rest = shift(#ARGV);
}
$opt_b[$bindex++] = $rest;
next;
}
if ($first eq "l") {
if ($rest eq '') {
die "No argument for option -l.\n" unless #ARGV;
$rest = shift(#ARGV);
}
$opt_l = $rest;
next;
}
if ($first eq "m") {
if($rest eq '') {
die "No argument for option -m.\n" unless #ARGV;
$rest = shift(#ARGV);
}
$opt_m = $rest;
next;
}
if ($first eq "c") {
if($rest eq '') {
die "No argument for option -c.\n" unless #ARGV;
$rest = shift(#ARGV);
}
$opt_c = $rest;
next;
}
if ($first eq "n") {
if($rest eq '') {
die "No argument for option -n.\n" unless #ARGV;
$rest = shift(#ARGV);
}
$opt_n = $rest;
next;
}
if ($first eq "x") {
$opt_x = 1;
next;
}
#
# Override the name of the server. This is used for testing this script.
#
if ($first eq "s") {
$server = shift(#ARGV);
next;
}
#
# Override the port. This is used for testing this script.
#
if ($first eq "p") {
$port = shift(#ARGV);
next;
}
die "Unrecognized option -$first. $usage\n";
}
#
# Check a bunch of things first to ensure that the
# script will be able to run to completion.
#
#
# Make sure all the argument files exist and are readable.
#
print "Checking files . . . \n";
$i = 0;
while($i < $bindex)
{
die "Base file $opt_b[$i] does not exist. $noreq\n" unless -e "$opt_b[$i]";
die "Base file $opt_b[$i] is not readable. $noreq\n" unless -r "$opt_b[$i]";
die "Base file $opt_b is not a text file. $noreq\n" unless -T "$opt_b[$i]";
$i++;
}
foreach $file (#ARGV)
{
die "File $file does not exist. $noreq\n" unless -e "$file";
die "File $file is not readable. $noreq\n" unless -r "$file";
die "File $file is not a text file. $noreq\n" unless -T "$file";
}
if ("#ARGV" eq '') {
die "No files submitted.\n $usage";
}
print "OK\n";
#
# Now the real processing begins.
#
$sock = new IO::Socket::INET (
PeerAddr => $server,
PeerPort => $port,
Proto => 'tcp',
);
die "Could not connect to server $server: $!\n" unless $sock;
$sock->autoflush(1);
sub read_from_server {
$msg = <$sock>;
print $msg;
}
sub upload_file {
local ($file, $id, $lang) = #_;
#
# The stat function does not seem to give correct filesizes on windows, so
# we compute the size here via brute force.
#
open(F,$file);
$size = 0;
while (<F>) {
$size += length($_);
}
close(F);
print "Uploading $file ...";
open(F,$file);
$file =~s/\s/\_/g; # replace blanks in filename with underscores
print $sock "file $id $lang $size $file\n";
while (<F>) {
print $sock $_;
}
close(F);
print "done.\n";
}
print $sock "moss $userid\n"; # authenticate user
print $sock "directory $opt_d\n";
print $sock "X $opt_x\n";
print $sock "maxmatches $opt_m\n";
print $sock "show $opt_n\n";
#
# confirm that we have a supported languages
#
print $sock "language $opt_l\n";
$msg = <$sock>;
chop($msg);
if ($msg eq "no") {
print $sock "end\n";
die "Unrecognized language $opt_l.";
}
# upload any base files
$i = 0;
while($i < $bindex) {
&upload_file($opt_b[$i++],0,$opt_l);
}
$setid = 1;
foreach $file (#ARGV) {
&upload_file($file,$setid++,$opt_l);
}
print $sock "query 0 $opt_c\n";
print "Query submitted. Waiting for the server's response.\n";
&read_from_server();
print $sock "end\n";
close($sock);
Thank you for any input you may have on my problem.
You can use my native Java client for MOSS instead .
Don't mind the version number. I've been using it in production successfully.

Powershell: Capturing standard out and error with Process object

I want to start a Java program from PowerShell and get the results printed on the console.
I have followed the instructions of this question:
Capturing standard out and error with Start-Process
But for me, this is not working as I expected. What I'm doing wrong?
This is the script:
$psi = New-object System.Diagnostics.ProcessStartInfo
$psi.CreateNoWindow = $true
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.FileName = 'java.exe'
$psi.Arguments = #("-jar","tools\compiler.jar","--compilation_level", "ADVANCED_OPTIMIZATIONS", "--js", $BuildFile, "--js_output_file", $BuildMinFile)
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $psi
$process.Start() | Out-Null
$process.WaitForExit()
$output = $process.StandardOutput.ReadToEnd()
$output
The $output variable is always empty (and nothing is printed on the console of course).
The docs on the RedirectStandardError property suggests that it is better to put the WaitForExit() call after the ReadToEnd() call. The following works correctly for me:
$psi = New-object System.Diagnostics.ProcessStartInfo
$psi.CreateNoWindow = $true
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.FileName = 'ipconfig.exe'
$psi.Arguments = #("/a")
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $psi
[void]$process.Start()
$output = $process.StandardOutput.ReadToEnd()
$process.WaitForExit()
$output
Small variation so that you can selectively print the output if needed. As in if your looking just for error or warning messages and by the way Keith you saved my bacon with your response...
$psi = New-object System.Diagnostics.ProcessStartInfo
$psi.CreateNoWindow = $true
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.FileName = 'robocopy'
$psi.Arguments = #("$HomeDirectory $NewHomeDirectory /MIR /XF desktop.ini /XD VDI /R:0 /W:0 /s /v /np")
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $psi
[void]$process.Start()
do
{
$process.StandardOutput.ReadLine()
}
while (!$process.HasExited)
Here is a modification to paul's answer, hopefully it addresses the truncated output. i did a test using a failure and did not see truncation.
function Start-ProcessWithOutput
{
param ([string]$Path,[string[]]$ArgumentList)
$Output = New-Object -TypeName System.Text.StringBuilder
$Error = New-Object -TypeName System.Text.StringBuilder
$psi = New-object System.Diagnostics.ProcessStartInfo
$psi.CreateNoWindow = $true
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.FileName = $Path
if ($ArgumentList.Count -gt 0)
{
$psi.Arguments = $ArgumentList
}
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $psi
[void]$process.Start()
do
{
if (!$process.StandardOutput.EndOfStream)
{
[void]$Output.AppendLine($process.StandardOutput.ReadLine())
}
if (!$process.StandardError.EndOfStream)
{
[void]$Error.AppendLine($process.StandardError.ReadLine())
}
Start-Sleep -Milliseconds 10
} while (!$process.HasExited)
#read remainder
while (!$process.StandardOutput.EndOfStream)
{
#write-verbose 'read remaining output'
[void]$Output.AppendLine($process.StandardOutput.ReadLine())
}
while (!$process.StandardError.EndOfStream)
{
#write-verbose 'read remaining error'
[void]$Error.AppendLine($process.StandardError.ReadLine())
}
return #{ExitCode = $process.ExitCode; Output = $Output.ToString(); Error = $Error.ToString(); ExitTime=$process.ExitTime}
}
$p = Start-ProcessWithOutput "C:\Program Files\7-Zip\7z.exe" -ArgumentList "x","-y","-oE:\PowershellModules",$NewModules.FullName -verbose
$p.ExitCode
$p.Output
$p.Error
the 10ms sleep is to avoid spinning cpu when nothing to read.
I was getting the deadlock scenario mentioned by Ash using Justin's solution. Modified the script accordingly to subscribe to async event handlers to get the output and error text which accomplishes the same thing but avoids the deadlock condition.
Seemed to resolve the deadlock issue in my testing without altering the return data.
# Define global variables used in the Start-ProcessWithOutput function.
$global:processOutputStringGlobal = ""
$global:processErrorStringGlobal = ""
# Launch an executable and return the exitcode, output text, and error text of the process.
function Start-ProcessWithOutput
{
# Function requires a path to an executable and an optional list of arguments
param (
[Parameter(Mandatory=$true)] [string]$ExecutablePath,
[Parameter(Mandatory=$false)] [string[]]$ArgumentList
)
# Reset our global variables to an empty string in the event this process is called multiple times.
$global:processOutputStringGlobal = ""
$global:processErrorStringGlobal = ""
# Create the Process Info object which contains details about the process. We tell it to
# redirect standard output and error output which will be collected and stored in a variable.
$ProcessStartInfoObject = New-object System.Diagnostics.ProcessStartInfo
$ProcessStartInfoObject.FileName = $ExecutablePath
$ProcessStartInfoObject.CreateNoWindow = $true
$ProcessStartInfoObject.UseShellExecute = $false
$ProcessStartInfoObject.RedirectStandardOutput = $true
$ProcessStartInfoObject.RedirectStandardError = $true
# Add the arguments to the process info object if any were provided
if ($ArgumentList.Count -gt 0)
{
$ProcessStartInfoObject.Arguments = $ArgumentList
}
# Create the object that will represent the process
$Process = New-Object System.Diagnostics.Process
$Process.StartInfo = $ProcessStartInfoObject
# Define actions for the event handlers we will subscribe to in a moment. These are checking whether
# any data was sent by the event handler and updating the global variable if it is not null or empty.
$ProcessOutputEventAction = {
if ($null -ne $EventArgs.Data -and $EventArgs.Data -ne ""){
$global:processOutputStringGlobal += "$($EventArgs.Data)`r`n"
}
}
$ProcessErrorEventAction = {
if ($null -ne $EventArgs.Data -and $EventArgs.Data -ne ""){
$global:processErrorStringGlobal += "$($EventArgs.Data)`r`n"
}
}
# We need to create an event handler for the Process object. This will call the action defined above
# anytime that event is triggered. We are looking for output and error data received by the process
# and appending the global variables with those values.
Register-ObjectEvent -InputObject $Process -EventName "OutputDataReceived" -Action $ProcessOutputEventAction
Register-ObjectEvent -InputObject $Process -EventName "ErrorDataReceived" -Action $ProcessErrorEventAction
# Process starts here
[void]$Process.Start()
# This sets up an asyncronous task to read the console output from the process, which triggers the appropriate
# event, which we setup handlers for just above.
$Process.BeginErrorReadLine()
$Process.BeginOutputReadLine()
# Wait for the process to exit.
$Process.WaitForExit()
# We need to wait just a moment so the async tasks that are reading the output of the process can catch
# up. Not having this sleep here can cause the return values to be empty or incomplete. In my testing,
# it seemed like half a second was enough time to always get the data, but you may need to adjust accordingly.
Start-Sleep -Milliseconds 500
# Return an object that contains the exit code, output text, and error text.
return #{
ExitCode = $Process.ExitCode;
OutputString = $global:processOutputStringGlobal;
ErrorString = $global:processErrorStringGlobal;
ExitTime = $Process.ExitTime
}
}

Perl Pipe not redirecting Java process output

I'm trying to control a game server and display it's output in real time. This is what I have so far:
#!/usr/bin/perl -w
use IO::Socket;
use Net::hostent; # for OO version of gethostbyaddr
$PORT = 9000; # pick something not in use
$server = IO::Socket::INET->new( Proto => 'tcp',
LocalPort => $PORT,
Listen => SOMAXCONN,
Reuse => 1);
die "can't setup server" unless $server;
print "[Server $0 accepting clients]\n";
while ($client = $server->accept()) {
$client->autoflush(1);
print $client "Welcome to $0; type help for command list.\n";
$hostinfo = gethostbyaddr($client->peeraddr);
printf "[Connect from %s]\n", $hostinfo->name || $client->peerhost;
print $client "Command? ";
while ( <$client>) {
next unless /\S/; # blank line
if (/quit|exit/i) {
last; }
elsif (/fail|omg/i) {
printf $client "%s\n", scalar localtime; }
elsif (/start/i ) {
if (my $ping_pid = open(JAVA, "screen java -jar craftbukkit-0.0.1-SNAPSHOT.jar |")) {
while (my $ping_output = <JAVA>) {
# Do something with the output, let's say print
print $client $ping_output;
# Kill the C program based on some arbitrary condition (in this case
# the output of the program itself).
}
}
printf $client "I think it started...\n Say status for output\n"; }
elsif (/stop/i ) {
print RSPS "stop";
close(RSPS);
print $client "Should be closed.\n"; }
elsif (/status/i ) {
$output = RSPS;
print $client $output; }
else {
print $client "FAIL\n";
}
} continue {
print $client "Command? ";
}
close $client;
}
It starts the process just fine, the only flaw is that it's not outputting the output of the Java process to the socket (It is displaying the output in the terminal window that Perl was initiated with) I've tried this with ping and it worked just fine, any ideas?
Thanks in advance!
It sounds like the Java code (or maybe it's screen) is printing some output to the standard error stream. Assuming that you don't want to capture it separately, some easy fixes are:
Suppress it:
open(JAVA, "screen java -jar craftbukkit-0.0.1-SNAPSHOT.jar 2>/dev/null |")
Capture it in the standard output stream:
open(JAVA, "screen java -jar craftbukkit-0.0.1-SNAPSHOT.jar 2>&1 |")
screen redirects the output to the "screen". Get rid of the screen in the command.

Categories