なんか 意識がホワイトアウトするんだが まあいいだろう。
PHP → C++ にデータは送れたのだった。
前回の記事 : http://qiita.com/muzudho1/items/f39f80957faaf6c58155
じゃあ、C++ → PHP の方向はできるのだろうか。調べてみよう。
C++ からエンキュー するには
「AMQP-CPP」(CopernicaMarketingSoftware/AMQP-CPP)
https://github.com/CopernicaMarketingSoftware/AMQP-CPP
ここの readme.MD テキストぐらいしか情報源が無いんだが、他にやってる人いないのかだぜ☆(^~^)?
これを使えばいいのでは?
// start a transaction
channel.startTransaction();
// publish a number of messages
channel.publish("my-exchange", "my-key", "my first message");
channel.publish("my-exchange", "my-key", "another message");
// commit the transactions, and set up callbacks that are called when
// the transaction was successful or not
channel.commitTransaction()
.onSuccess([]() {
// all messages were successfully published
})
.onError([]() {
// none of the messages were published
// now we have to do it all over again
});
どう使えばいいのか分からないが 適当に書いて動かす。
tamesi29a11_enqueue.cpp
#include <ev.h>
#include <amqpcpp.h>
#include <amqpcpp/libev.h>
int main()
{
// access to the event loop
auto *loop = EV_DEFAULT;
// handler for libev (so we don't have to implement AMQP::TcpHandler!)
AMQP::LibEvHandler handler(loop);
// make a connection
AMQP::TcpConnection connection(&handler, AMQP::Address("amqp://localhost/"));
// we need a channel too
AMQP::TcpChannel channel(&connection);
// create a custom callback
auto callback = [](const std::string &name, int msgcount, int consumercount) {
// @todo add your own implementation
// report the name of the temporary queue
std::cout << "(^q^)declared queue " << name << std::endl;
// now we can close the connection
// connection.close();
};
// declare the queue, and install the callback that is called on success
channel.declareQueue("1111").onSuccess(callback);
// start a transaction
channel.startTransaction();
// publish a number of messages
channel.publish("my-exchange", "1111", "alpaca");
channel.publish("my-exchange", "1111", "bear");
channel.publish("my-exchange", "1111", "cat");
channel.publish("my-exchange", "1111", "dog");
channel.publish("my-exchange", "1111", "elephant");
// commit the transactions, and set up callbacks that are called when
// the transaction was successful or not
channel.commitTransaction()
.onSuccess([]() {
// all messages were successfully published
})
.onError([]() {
// none of the messages were published
// now we have to do it all over again
});
// done
return 0;
}
# g++ -std=c++11 tamesi29a11_enqueue.cpp -lev -lamqpcpp -pthread -o tamesi29a11_enqueue.exe
tamesi29a11_enqueue.cpp: In function ‘int main()’:
tamesi29a11_enqueue.cpp:37:52: error: no matching function for call to ‘AMQP::TcpChannel::publish(const char [12], const char [5], const char [7])’
channel.publish("my-exchange", "1111", "alpaca");
^
In file included from /usr/include/amqpcpp.h:69:0,
from tamesi29a11_enqueue.cpp:2:
/usr/include/amqpcpp/channel.h:346:10: note: candidate: bool AMQP::Channel::publish(const string&, const string&, const AMQP::Envelope&)
bool publish(const std::string &exchange, const std::string &routingKey, const Envelope &envelope) { return _implementation->publish(exchange, routingK
^
/usr/include/amqpcpp/channel.h:346:10: note: no known conversion for argument 3 from ‘const char [7]’ to ‘const AMQP::Envelope&’
/usr/include/amqpcpp/channel.h:347:10: note: candidate: bool AMQP::Channel::publish(const string&, const string&, const char*, size_t)
bool publish(const std::string &exchange, const std::string &routingKey, const char *message, size_t size) { return _implementation->publish(exchange,
^
なんか いっぱいエラー。サンプル・プログラム間違ってんじゃないか。
/usr/include/amqpcpp/envelope.cpp 抜粋
/**
* Constructor
*
* The data buffer that you pass to this constructor must be valid during
* the lifetime of the Envelope object.
*
* @param body
* @param size
*/
Envelope(const char *body, uint64_t size) : MetaData(), _body((char *)body), _bodySize(size) {}
これを使えばいいんじゃないか?
// publish a number of messages
AMQP::Envelope msg1("alpaca" , strlen("alpaca" ));
AMQP::Envelope msg2("bear" , strlen("bear" ));
AMQP::Envelope msg3("cat" , strlen("cat" ));
AMQP::Envelope msg4("dog" , strlen("dog" ));
AMQP::Envelope msg5("elephant", strlen("elephant"));
channel.publish("my-exchange", "1111", msg1);
channel.publish("my-exchange", "1111", msg2);
channel.publish("my-exchange", "1111", msg3);
channel.publish("my-exchange", "1111", msg4);
channel.publish("my-exchange", "1111", msg5);
こんなんでいいんだろうか?
# g++ -std=c++11 tamesi29a11_enqueue.cpp -lev -lamqpcpp -pthread -o tamesi29a11_enqueue.exe
tamesi29a11_enqueue.cpp: In function ‘int main()’:
tamesi29a11_enqueue.cpp:57:10: error: no matching function for call to ‘AMQP::Deferred::onError(main()::<lambda()>)’
});
^
In file included from /usr/include/amqpcpp.h:62:0,
from tamesi29a11_enqueue.cpp:2:
/usr/include/amqpcpp/deferred.h:239:15: note: candidate: AMQP::Deferred& AMQP::Deferred::onError(const ErrorCallback&)
Deferred &onError(const ErrorCallback &callback)
^
/usr/include/amqpcpp/deferred.h:239:15: note: no known conversion for argument 1 from ‘main()::<lambda()>’ to ‘const ErrorCallback& {aka const std::function<void(const char*)>&}’
エラーの数は減った。
こうしてどうか。
auto errorCb = [](const char *message) {
// none of the messages were published
// now we have to do it all over again
std::cout << "(^q^)publish operation failed message=[" << message<< "]" << std::endl;
};
// commit the transactions, and set up callbacks that are called when
// the transaction was successful or not
channel.commitTransaction()
.onSuccess([]() {
// all messages were successfully published
})
.onError(errorCb);
コンパイルは通った。
# ./tamesi29a11_enqueue.exe
実行はでけたが、どうなったのか?
# rabbitmqctl list_queues
Listing queues ...
1111 0
違うのか。
じゃあこうならどうか?
channel.publish("1111", "", msg1);
channel.publish("1111", "", msg2);
channel.publish("1111", "", msg3);
channel.publish("1111", "", msg4);
channel.publish("1111", "", msg5);
変わらない。
じゃあこれでどうか?
channel.publish("my-exchange", "my-key", msg1);
channel.publish("my-exchange", "my-key", msg2);
channel.publish("my-exchange", "my-key", msg3);
channel.publish("my-exchange", "my-key", msg4);
channel.publish("my-exchange", "my-key", msg5);
だめ。
// use the channel object to call the AMQP method you like
channel.declareExchange("my-exchange", AMQP::fanout);
channel.declareQueue("my-queue");
channel.bindQueue("my-exchange", "my-queue", "my-routing-key");
このコードが要るんじゃないか?
だめ。
channel.bindQueue("my-exchange", "1111", "my-routing-key");
こうか?
だめ。
channel.publish("my-exchange", "my-key", 0, "alpaca");
こうとか?
コンパイル・エラー。
channel.publish("my-exchange", "my-key", "alpaca", strlen("alpaca"));
これは?
だめ。
channel.publish("my-exchange", "my-key", "alpaca", 6);
こうなら?
だめ。
channel.publish("my-exchange", "", "alpaca", 6);
これは?
だめ。
my-exchange を全部 空文字列にしたら?
/usr/include/amqpcpp.h 抜粋
/**
* Publish a message to an exchange
*
* @param exchange the exchange to publish to
* @param routingkey the routing key
* @param envelope the full envelope to send
* @param message the message to send
* @param size size of the message
*/
bool publish(const std::string &exchange, const std::string &routingKey, const Envelope &envelope) { return _implementation->publish(exchange, routingKey, envelope); }
bool publish(const std::string &exchange, const std::string &routingKey, const char *message, size_t size) { return _implementation->publish(exchange, routingKey, Envelope(message, size)); }
publishメソッドの実装、2つしかないじゃないか。
/**
* Start a transaction
*
* This function returns a deferred handler. Callbacks can be installed
* using onSuccess(), onError() and onFinalize() methods.
*/
Deferred &startTransaction()
{
return _implementation->startTransaction();
}
/**
* Commit the current transaction
*
* This function returns a deferred handler. Callbacks can be installed
* using onSuccess(), onError() and onFinalize() methods.
*/
Deferred &commitTransaction()
{
return _implementation->commitTransaction();
}
どうやったら動くかな。
// make a connection
// AMQP::TcpConnection connection(&handler, AMQP::Address("amqp://localhost/"));
// create a AMQP connection object
AMQP::Connection connection(&myHandler, AMQP::Login("guest","guest"), "/");
接続は guest, guest だった気もするな。
コンパイル・エラー。
/usr/include/amqpcpp/connection.h 抜粋
public:
/**
* Construct an AMQP object based on full login data
*
* The first parameter is a handler object. This handler class is
* an interface that should be implemented by the caller.
*
* @param handler Connection handler
* @param login Login data
* @param vhost Vhost to use
*/
Connection(ConnectionHandler *handler, const Login &login, const std::string &vhost) : _implementation(this, handler, login, vhost) {}
/**
* Construct with default vhost
* @param handler Connection handler
* @param login Login data
*/
Connection(ConnectionHandler *handler, const Login &login) : _implementation(this, handler, login, "/") {}
/**
* Construct an AMQP object with default login data and default vhost
* @param handler Connection handler
*/
Connection(ConnectionHandler *handler, const std::string &vhost) : _implementation(this, handler, Login(), vhost) {}
/**
* Construct an AMQP object with default login data and default vhost
* @param handler Connection handler
*/
Connection(ConnectionHandler *handler) : _implementation(this, handler, Login(), "/") {}
/**
* No copy'ing, we do not support having two identical connection objects
* @param connection
*/
Connection(const Connection &connection) = delete;
どれを使うんだ。
/usr/include/amqpcpp/connectionhandler.h
例えば、
// create an instance of your own connection handler
ConnectionHandler myHandler;
こんなん要るのか?
#include <ev.h>
#include <amqpcpp.h>
#include <amqpcpp/libev.h>
class MyConnectionHandler : public AMQP::ConnectionHandler
{
/**
* Method that is called by the AMQP library every time it has data
* available that should be sent to RabbitMQ.
* @param connection pointer to the main connection object
* @param data memory buffer with the data that should be sent to RabbitMQ
* @param size size of the buffer
*/
virtual void onData(AMQP::Connection *connection, const char *data, size_t size)
{
// @todo
// Add your own implementation, for example by doing a call to the
// send() system call. But be aware that the send() call may not
// send all data at once, so you also need to take care of buffering
// the bytes that could not immediately be sent, and try to send
// them again when the socket becomes writable again
}
/**
* Method that is called by the AMQP library when the login attempt
* succeeded. After this method has been called, the connection is ready
* to use.
* @param connection The connection that can now be used
*/
virtual void onConnected(AMQP::Connection *connection)
{
// @todo
// add your own implementation, for example by creating a channel
// instance, and start publishing or consuming
}
/**
* Method that is called by the AMQP library when a fatal error occurs
* on the connection, for example because data received from RabbitMQ
* could not be recognized.
* @param connection The connection on which the error occured
* @param message A human readable error message
*/
virtual void onError(AMQP::Connection *connection, const char *message)
{
// @todo
// add your own implementation, for example by reporting the error
// to the user of your program, log the error, and destruct the
// connection object because it is no longer in a usable state
}
/**
* Method that is called when the connection was closed. This is the
* counter part of a call to Connection::close() and it confirms that the
* connection was correctly closed.
*
* @param connection The connection that was closed and that is now unusable
*/
virtual void onClosed(AMQP::Connection *connection) {}
};
int main()
{
// create an instance of your own connection handler
MyConnectionHandler myHandler;
// create a AMQP connection object
AMQP::Connection connection(&myHandler, AMQP::Login("guest","guest"));
// and create a channel
AMQP::Channel channel(&connection);
// use the channel object to call the AMQP method you like
channel.declareQueue("1111");
channel.bindQueue("", "1111", "my-routing-key");
// start a transaction
channel.startTransaction();
// publish a number of messages
channel.publish("", "", "my first message", strlen("my first message") );
channel.publish("", "", "another message", strlen("another message" ) );
// commit the transactions, and set up callbacks that are called when
// the transaction was successful or not
channel.commitTransaction();
// done
return 0;
}
だめ。
Connection と TcpConnection
2つあるんだが、TcpConnection で書き直すか。
/usr/include/amqpcpp/tcpconnection.h 抜粋
public:
/**
* Constructor
* @param handler User implemented handler object
* @param hostname The address to connect to
*/
TcpConnection(TcpHandler *handler, const Address &address);
#include <ev.h>
#include <amqpcpp.h>
#include <amqpcpp/libev.h>
int main()
{
// access to the event loop
auto *loop = EV_DEFAULT;
// handler for libev (so we don't have to implement AMQP::TcpHandler!)
AMQP::LibEvHandler handler(loop);
// make a connection
AMQP::TcpConnection connection(&handler, AMQP::Address("amqp://localhost/"));
// we need a channel too
AMQP::TcpChannel channel(&connection);
// use the channel object to call the AMQP method you like
channel.declareQueue("1111");
channel.bindQueue("", "1111", "");
// start a transaction
channel.startTransaction();
// publish a number of messages
channel.publish("", "", "my first message", strlen("my first message") );
channel.publish("", "", "another message", strlen("another message" ) );
// commit the transactions, and set up callbacks that are called when
// the transaction was successful or not
channel.commitTransaction();
// done
return 0;
}
channel.close();
connection.close();
閉じるのを足しても変わらず。
ソースを読もう
/usr/include/amqpcpp/address.h 抜粋
/**
* Address.h
*
* An AMQP address in the "amqp://user:password@hostname:port/vhost" notation
*
* @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
* @copyright 2015 Copernica BV
*/
この書式をしっかり書いた方がいいのだろうか?
/**
* Port number
* @var uint16_t
*/
uint16_t _port = 5672;
C++からエンキューできないとする
代わりに どのようにして PHP に出力を返す方法があるだろうか?
C# の方をもう少し改造してみる。
C# から、エンキューはできる。
//--------------------------------------------------------------------------------
// コマンドライン例
//
// # コンパイル
// mcs /r:RabbitMQ.Client.dll -define:UBUNTU tamesi30a2.cs
//
// # キューの中身の数を調べる
// rabbitmqctl list_queues
//--------------------------------------------------------------------------------
//
// Ubuntu の RabbitMQ はソースのバージョンが古いのか、API が異なった。
// #define UBUNTU
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Text;
namespace UsagiMQ
{
/// <summary>
/// 参照 : 「QueueDeclare」 http://docs.spring.io/spring-amqp-net/docs/1.0.x/api/html/Spring.Messaging.Amqp.Rabbit~Spring.Messaging.Amqp.Rabbit.Connection.CachedModel~QueueDeclare(String,Boolean,Boolean,Boolean,Boolean,Boolean,IDictionary).html
/// 参照 : 「EventingBasicConsumer」 https://www.rabbitmq.com/releases/rabbitmq-dotnet-client/v1.4.0/rabbitmq-dotnet-client-1.4.0-net-2.0-htmldoc/type-RabbitMQ.Client.Events.EventingBasicConsumer.html
/// 参照 : 「BasicConsume」 https://www.rabbitmq.com/releases/rabbitmq-dotnet-client/v1.4.0/rabbitmq-dotnet-client-1.4.0-net-2.0-htmldoc/type-RabbitMQ.Client.IModel.html#method-M:RabbitMQ.Client.IModel.BasicConsume(System.UInt16,System.String,System.Boolean,System.Collections.IDictionary,RabbitMQ.Client.IBasicConsumer)
/// </summary>
class Program
{
public const string
HOST_NAME = "localhost",
QUEUE_NAME = "1111";
public static ConnectionFactory GetFactory()
{
if(null== m_factory_)
{
m_factory_ = new ConnectionFactory() { HostName = HOST_NAME };
}
return m_factory_;
}
static ConnectionFactory m_factory_;
public static IConnection GetConnection()
{
if (null==m_connection_)
{
m_connection_ = GetFactory().CreateConnection();
}
return m_connection_;
}
static IConnection m_connection_;
public static IModel GetChannel()
{
if (null==m_channel_)
{
m_channel_ = GetConnection().CreateModel();
#if UBUNTU
// Ubuntuでは何故か Spring.Messaging.Amqp.Rabbit の引数 7 つのやつになっている。
m_channel_.QueueDeclare(QUEUE_NAME, false, false, false, false, false, null);
#else
m_channel_.QueueDeclare(QUEUE_NAME, false, false, false, null);
#endif
}
return m_channel_;
}
static IModel m_channel_;
public static EventingBasicConsumer GetConsumer()
{
if (null == m_consumer_)
{
#if UBUNTU
// Ubuntuでは何故か v1.4.0 の引数が 0 個のやつになっている。調べたが引数が1個~6個のものは無かった。
m_consumer_ = new EventingBasicConsumer();
#else
m_consumer_ = new EventingBasicConsumer(GetChannel());
#endif
}
return m_consumer_;
}
static EventingBasicConsumer m_consumer_;
/// <summary>
/// 対応するオープンは無いけれど、開けたら閉める、を完璧に対応する必要がある。
/// </summary>
static void CloseConnection()
{
if (null != m_connection_)
{
m_connection_.Close();
m_connection_ = null;
}
}
/// <summary>
/// 対応するオープンは無いけれど、開けたら閉める、を完璧に対応する必要がある。
/// </summary>
static void CloseChannel()
{
if (null != m_channel_)
{
m_channel_.Close();
m_channel_ = null;
}
}
static void Main(string[] args)
{
for (;;)
{
Console.WriteLine(@"選べだぜ☆(^~^)
1 : メッセージ エンキュー
quit: 終了
");
int category = 0;
for (;;)
{
string line = Console.ReadLine();
switch (line)
{
case "1": category = 1; goto gt_EndLoop1;
case "quit": goto gt_Quit;
default: break;
}
}
gt_EndLoop1:
;
switch (category)
{
case 1:
{
Console.WriteLine(@"メッセージを書いて[Enter]キーを押せだぜ☆(^~^)");
// "Hello World!" などを入力
string line = Console.ReadLine();
Enqueue(line);
}
break;
}
}
gt_Quit:
// 対応するオープンは無いが、ちゃんと閉じないと、プロセスが終わってくれない。
CloseConnection();
}
static void Enqueue(string message)
{
IModel channel = GetChannel();
byte[] body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish("", QUEUE_NAME, null, body);
Console.WriteLine(" Enqueue(^q^) {0}", message);
// 対応するオープンは無いが、ちゃんと閉じないと、レシーブしてくれない。
CloseChannel();
}
}
}
PHPでのデキューは
loop6.php
<?php
// デキュー用
// サーバーの外部からはアクセスできないようにすること。
//
// このプログラムは、コマンドラインで実行する
// php loop6.php
// あるいは
// nohup /usr/bin/php /home/★user/shogi/php_service/loop6.php > /home/★user/shogi/php_log/loop6.out.log 2> /home/★user/shogi/php_log/loop6.err.log < /dev/null &
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
// プロセス間通信の前準備をするぜ☆(^~^)
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();
$QKey = '1111';
$channel->queue_declare($QKey, false, false, false, false);
// キューを開いてしまえば、あとは無限ループ!
// デキューしたタイミングですることをここに書く
$callback = function($msg) {
echo " [x] Received ", $msg->body, "\n";
};
$channel->basic_consume($QKey, '', false, true, false, false, $callback);
// 無限ループ
while(count($channel->callbacks))
{
// ここでブロックしながらデキューする
$channel->wait();
}
// ここに来ない
// $channel->close();
// $connection->close();
分からないので質問を投げた。
「How to publish messages #109 (2) #120」(CopernicaMarketingSoftware/AMQP-CPP)
https://github.com/CopernicaMarketingSoftware/AMQP-CPP/issues/120
// OS : Ubuntu 16.04
// Server : Sakura VPS (Rental)
// Library : libev
// : Install : Command : sudo apt-get update
// : sudo apt-get install libev-dev
// Service : RabbitMQ
// : Reference : Web site : Top page http://www.rabbitmq.com/
// : Install : Web site : Installing on Debian / Ubuntu http://www.rabbitmq.com/install-debian.html
// : Manual : Command : man rabbitmqctl
// : Start : Command : rabbitmq-server
// : Stop : Command : rabbitmqctl stop
// : Check : Command : rabbitmqctl status
// : : Command : rabbitmqctl list_queues
// Library : AMQP-CPP
// : Reference : Web site : AMQP-CPP README.md https://github.com/CopernicaMarketingSoftware/AMQP-CPP
// : Directory : Command : cd /usr/include/amqpcpp/
// : Compile : Command : g++ -std=c++11 publish.cpp -o publish.exe -lev -lamqpcpp -pthread
// : Execute : Command : ./publish.exe
//
// publish.cpp
// Reffered source code : how to publish messages #109 https://github.com/CopernicaMarketingSoftware/AMQP-CPP/issues/109
#include <iostream>
#include <string>
#include <ev.h>
#include <amqpcpp.h>
#include <amqpcpp/libev.h>
auto* loop = EV_DEFAULT;
AMQP::LibEvHandler handler{loop};
AMQP::Address address{"amqp://localhost:5672"};
AMQP::TcpConnection connection{&handler, address};
AMQP::TcpChannel channel{&connection};
std::string exchange_name = "myexchange";
std::string queue_name = "myqueue";
std::string routing_key = "";
int main(int argc, char* argv[]) {
channel.declareExchange(exchange_name, AMQP::direct, AMQP::durable);
channel.declareQueue(queue_name, AMQP::durable)
.onSuccess([](const std::string& name, uint32_t messages, uint32_t consumers) {
std::cout << "declared queue " << name << " (messages: " << messages << ", consumers: " << consumers << ")\n";
// break in ev loop.
connection.close();
})
.onError([](const char* msg) {
std::cout << "error declaring queue: " << msg << "\n";
});
std::cout << "channel.connected: " << channel.connected() << "\n";
std::string msg = "hello, japan";
if (channel.publish(exchange_name, routing_key, msg.c_str(), msg.size())) {
std::cout << "publish ok\n";
} else {
std::cout << "failed to publish?\n";
}
// We will monitor until the connection is lost. Execute channel.declareQueue( ... ).
ev_run(loop);
return 0;
}
/*
# ./publish.exe
channel.connected: 1
publish ok
declared queue myqueue (messages: 0, consumers: 0)
# rabbitmqctl list_queues
Listing queues ...
myqueue 0
*/
C#の無限ループは常駐させておけるだろうか?
loop28.cs
// Compile : Command : mcs loop28.cs
// Execute : Command : ./loop28.exe
using System.Threading;
class Loop28
{
static void Main(string[] args)
{
for (;;)
{
Thread.Sleep(1);
}
}
}
バックグラウンドで実行してログアウト。
# ps aux | grep ./loop28.exe
root 1489 4.0 1.0 126580 10976 ? Sl 07:00 0:04 /usr/bin/cli ./loop28.exe
root 1580 0.0 0.0 12936 988 pts/5 S+ 07:02 0:00 grep --color=auto ./loop28.exe
ジョブからは消えたが、プロセスを見ると「/usr/bin/cli ./loop28.exe」は動いているんじゃないか?
# ps aux | grep loop28
root 1489 4.1 1.0 126580 10976 ? Sl 07:00 0:16 /usr/bin/cli ./loop28.exe
root 1641 0.0 0.0 12936 988 pts/5 S+ 07:07 0:00 grep --color=auto loop28
root 20615 0.0 1.3 230188 13304 ? S Mar10 0:11 php loop28.php
PHP の loop28 もまだ生きているようだ。C++のは見当たらない。あるいは C++ の loop28なのか?
# ps aux | grep loop28
root 1489 3.9 1.0 126580 10976 ? Sl 07:00 0:35 /usr/bin/cli . loop28.exe
root 1743 3.5 1.0 126580 10972 ? Sl 07:09 0:12 /usr/bin/cli . loop28_cs.exe
root 1820 0.0 0.0 4216 368 ? S 07:13 0:00 ./loop28_cpp.ex e
root 1889 0.0 0.0 12936 984 pts/6 S+ 07:15 0:00 grep --color=au to loop28
root 20615 0.0 1.3 230188 13304 ? S Mar10 0:11 php loop28.php
root@tk2-217-18401:~# ps aux | grep loop28
root 1489 3.9 1.0 126580 10976 ? Rl 07:00 0:35 /usr/bin/cli ./loop28.exe
root 1743 3.5 1.0 126580 10972 ? Sl 07:09 0:12 /usr/bin/cli ./loop28_cs.exe
root 1820 0.0 0.0 4216 368 ? S 07:13 0:00 ./loop28_cpp.exe
root 1891 0.0 0.0 12936 984 pts/6 S+ 07:15 0:00 grep --color=auto loop28
root 20615 0.0 1.3 230188 13304 ? S Mar10 0:11 php loop28.php
名前を分けてみたが動いているようだ。
# kill 1489
じゃあ、外部プロセスA を起動して無限ループに入ると、外部プロセスA も常駐できるのだろうか?
# ./apery &
[1] 1944
root@tk2-217-18401:/home/★user/shogi/ukamuse_sdt4/bin# logout
There are stopped jobs.
[1]+ Stopped ./apery
# sudo su -
# ps aux | grep apery
root 1944 0.2 14.0 1325848 142872 pts/6 Tl 07:18 0:00 ./apery
root 1983 0.0 0.0 12936 988 pts/6 S+ 07:20 0:00 grep --color=auto apery
apery のプロセスも生きてるのかな?
# ps aux | grep apery
root 2048 0.0 0.0 12936 984 pts/0 S+ 07:21 0:00 grep --color=auto apery
ログインし直すといなくなっている。
# ps aux | grep loop28
root 1743 3.9 1.0 126580 10972 ? Sl 07:09 0:29 /usr/bin/cli ./loop28_cs.exe
root 1820 0.0 0.0 4216 368 ? S 07:13 0:00 ./loop28_cpp.exe
root 2061 0.0 0.0 12936 984 pts/0 R+ 07:22 0:00 grep --color=auto loop28
root 20615 0.0 1.3 230188 13304 ? S Mar10 0:11 php loop28.php
他のC++ と何が違うのか?
ためしさん31
こんなんでいいんだろうか?
// Compile : Command : mcs tamesi31.cs
// Execute : Command : ./tamesi31.exe ../ukamuse_sdt4/bin/apery
//
// tamesi31_cs.cs
using System.Threading;
using System.Diagnostics;
// Referred : 外部アプリケーションを起動する、ファイルを関連付けられたソフトで開く (DOBON.NET) http://dobon.net/vb/dotnet/process/shell.html
class Tamesi31
{
static Process process;
static void Main(string[] args)
{
// 外部プロセスを起動します。
if (2 < args.Length)
{
process = System.Diagnostics.Process.Start(
args[0],//"notepad.exe"
args[1]// @"""C:\test\1.txt"""
);
}
else if (1 < args.Length)
{
process = System.Diagnostics.Process.Start(
args[0]//"notepad.exe"
);
}
for (;;)
{
Thread.Sleep(1);
}
}
}
この方法だと 標準入出力が生きてないんで、別の方法で。
tamesi32a1_cs.cs
// Compile : Command : mcs tamesi32a1_cs.cs
// : Command : chmod 755 tamesi32a1_cs.cs
// Execute : Command : ./tamesi32a1_cs.exe
//
// tamesi32a1_cs.cs
using System;
using System.Diagnostics;
// Referred : 子プロセスの標準入出力 (smdn) http://smdn.jp/programming/netfx/standard_streams/1_process/
class Sample
{
static void Main()
{
// 子プロセスchild.exeの起動パラメータを作成する
ProcessStartInfo psi = new ProcessStartInfo("tamesi32a2_cs.exe");
psi.UseShellExecute = false; // シェルを使用せず子プロセスを起動する(リダイレクトするために必要)
psi.RedirectStandardInput = true; // 子プロセスの標準入力をリダイレクトする
// 子プロセスを起動する
using (Process child = Process.Start(psi))
{
for(;;)
{
Console.WriteLine("選べだぜ☆m9(^◇^)");
Console.WriteLine("1 : 子プロセスと送受信");
Console.WriteLine("quit : 終了");
string line = Console.ReadLine();
switch (line)
{
case "1":
{
// リダイレクトした子プロセスの標準入力にテキストを書き込む
child.StandardInput.WriteLine("line1");
child.StandardInput.WriteLine("line2");
child.StandardInput.WriteLine("line3");
}
break;
case "quit": goto gt_EndLoop;
}
}
gt_EndLoop:
// 子プロセスの標準入力を閉じて書き込みを終了する
child.StandardInput.Close();
// 子プロセスの終了を待機する
child.WaitForExit();
}
}
}
tamesi32a2_cs.cs
// Compile : Command : mcs tamesi32a2_cs.cs
// : Command : chmod 755 tamesi32a2_cs.cs
// Execute : Command : ./tamesi32a2_cs.exe
//
// tamesi32a2_cs.cs
using System;
class Sample
{
static void Main()
{
int lineNumber = 0;
while (true)
{
string line = Console.ReadLine();
if (line == null)
{
break;
}
else {
lineNumber++;
Console.WriteLine("(^q^)I am a child. {0}: {1}", lineNumber, line);
}
}
}
}
これは Ubuntu でも動いた。
./tamesi32a1_cs.exe > tamesi32a1_cs.out.log 2> tamesi32a1_cs.err.log < /dev/null &
バックグラウンドで動かすには、こんなんでいいんだろうか?
# jobs
[1] Running ./tamesi31_cs.exe ../ukamuse_sdt4/bin/apery &
[2]- Stopped ./tamesi31_cs.exe ../ukamuse_sdt4/bin/apery
[3]+ Stopped ./tamesi32a1_cs.exe
[4] Running ./tamesi32a1_cs.exe > tamesi32a1_cs.out.log 2> tamesi32a1_cs.err.log < /dev/null &
なんやかやと動いている。 4 番目のがさっきのやつか。
ログアウトしてみる。
再ログインしてみる。
# ps aux | grep tamesi32
root 3757 98.9 1.4 129860 14376 ? Rl 09:04 1:42 /usr/bin/cli ./tamesi32a1_cs.exe
root 3761 0.0 0.8 126864 9108 ? Sl 09:04 0:00 /usr/bin/mono-sgen tamesi32a2_cs.exe
root 3836 0.0 0.0 12936 988 pts/6 S+ 09:06 0:00 grep --color=auto tamesi32
フォアグラウンドに持ってきたら叩けるんだろうか?
ジョブじゃないから どうやって フォアグラウンドに持ってくるのか?
「バックグラウンドプロセス(ジョブ)の管理Add Star」(Linux初心者Tips)
http://d.hatena.ne.jp/satake7/20080606/p1
fg
と叩けばいいんだろうか?
# fg
-su: fg: current: no such job
「ログアウトしてもバックグラウンド ジョブを継続する方法」(ソースコード探検隊)
https://www.codereading.com/nb/ignore-the-hangup-signal.html
kill コマンドで再起動できないか?
「【 kill 】 プロセスおよびジョブを強制終了する」(ITPro)
http://itpro.nikkeibp.co.jp/article/COLUMN/20060227/230806/
「【 プログラムを再起動する 】」(ITPro)
http://itpro.nikkeibp.co.jp/article/COLUMN/20060228/231187/
kill -HUP 3757
再起動なのか?これ?
# ps aux | grep tamesi32
root 4272 0.0 0.0 12936 988 pts/6 S+ 09:24 0:00 grep --color=auto tamesi32
とどめを刺したような気がするんだが。2匹とも死んでしまったぜ。
サービスなら再起動で良かったが、さっきのは プロセスをフォアグラウンドに持ってきたかっただけじゃなかったか。
# man cli
で調べると cli は mono だったのか。
バックグラウンド・プロセスはどうやって 再起動するんだ?
# cli ./tamesi32a1_cs.exe
これで C# のプログラムは実行できるのか。
[Ctrl]+[Z] から bg 1。
fg で復帰した直後は、Console.ReadLine() でブロックされているところから始まるので、
1 [Enter] と打つと反応を返してくれる。
# ps aux | grep tamesi32
root 4427 0.0 1.4 129464 14592 pts/6 Tl 09:35 0:00 cli ./tamesi32a1_cs.exe
root 4430 0.0 1.0 126864 10736 pts/6 Tl 09:35 0:00 /usr/bin/mono-sgen tamesi32a2_cs.exe
root 4479 0.0 0.0 12936 988 pts/6 S+ 09:38 0:00 grep --color=auto tamesi32
こういう状況でまたログアウト。
# logout
$ logout
再度ログイン。
# ps aux | grep tamesi32
root 4620 0.0 0.0 12936 988 pts/6 S+ 09:40 0:00 grep --color=auto tamesi32
あれっ、消えてる。 cli で実行したらダメなのか、あるいは bg 1 ではダメなのか?
# ./tamesi32a1_cs.exe > tamesi32a1_cs.out.log 2> tamesi32a1_cs.err.log < /dev/null &
[1] 4665
# jobs
[1]+ Running ./tamesi32a1_cs.exe > tamesi32a1_cs.out.log 2> tamesi32a1_cs.err.log < /dev/null &
# ps aux | grep tamesi32
root 4665 99.2 1.8 129860 18372 pts/6 Rl 09:43 0:18 /usr/bin/cli ./tamesi32a1_cs.exe
root 4669 0.1 1.4 126864 14564 pts/6 Sl 09:43 0:00 /usr/bin/mono-sgen tamesi32a2_cs.exe
root 4677 0.0 0.0 12936 988 pts/6 S+ 09:43 0:00 grep --color=auto tamesi32
ここで
# fg
./tamesi32a1_cs.exe > tamesi32a1_cs.out.log 2> tamesi32a1_cs.err.log < /dev/null
入力待ちになっている。
1
反応なし。確かに
< /dev/null
とは書いたが、リダイレクトが必要か?
^Z
[1]+ Stopped ./tamesi32a1_cs.exe > tamesi32a1_cs.out.log 2> tamesi32a1_cs.err.log < /dev/null
どうやってリダイレクトするんだ?
top
と打つと タスクマネージャーみたいなのが出てくるが 関係ない。「q」と打って抜ける。
「How To Use Bash's Job Control to Manage Foreground and Background Processes」(DigitalOcean)
https://www.digitalocean.com/community/tutorials/how-to-use-bash-s-job-control-to-manage-foreground-and-background-processes
# bg
# fg
と2回打つといいのか? bg は バックグランドで止まっているジョブを再開させるのか?
英語が読めない
Note that not all commands can be backgrounded. Some processes will automatically terminate if they detect that they have been started with their standard input and output directly connected to an active terminal.
なんか書いてるが よくわからない。
デーモンについて調べよう。
標準入力を捨てない場合
その前に、標準出力を捨てていたのもダメなんじゃないか?
./tamesi32a1_cs.exe 2> tamesi32a1_cs.err.log &
こうすると どうなるのか?
「bg」「fg」で行ったり来たりできるようになった。
この状態でログアウトすると
# logout
There are stopped jobs.
ジョブが切られてしまった。 apery のときと同じ現象だ。
# jobs
[1]+ Stopped ./tamesi32a1_cs.exe 2> tamesi32a1_cs.err.log
だが、ストップしただけで、jobs ではまだ見れるようだが。
# logout
$ logout
ログインし直す。
# jobs
# ps aux | grep tamesi32
root 5487 0.0 0.0 12936 988 pts/6 S+ 10:19 0:00 grep --color=auto tamesi32
いなくなっている。じゃあ nohup を試すか。
# cd /home/★user/shogi/csharp_service
# nohup ./tamesi32a1_cs.exe 2> tamesi32a1_cs.err.log &
[1] 5521
# jobs
[1]+ Exit 1 nohup ./tamesi32a1_cs.exe 2> tamesi32a1_cs.err.log
# bg
-su: bg: current: no such job
# fg
-su: fg: current: no such job
# jobs
これまた どういうことか。
じゃあ絶対パスで。
# nohup /home/★user/shogi/csharp_service/tamesi32a1_cs.exe 2> /home/★user/shogi/csharp_service/tamesi32a1_cs.err.log &
[2] 5594
# jobs
[2]+ Exit 1 nohup /home/★user/shogi/csharp_service/tamesi32a1_cs.exe 2> /home/★user/shogi/csharp_service/tamesi32a1_cs.err.log
# jobs
消えてった。Exit 1 とは何だろうか?
「What does a “[1]+ Exit 1” response mean?」(Unit & Linux)
http://unix.stackexchange.com/questions/69137/what-does-a-1-exit-1-response-mean
exit(1) らしい。異常終了か。エラーログを見よう。
nohup: ignoring input and appending output to 'nohup.out'
Unhandled Exception:
System.UnauthorizedAccessException: Access to the path "/home/★user/shogi/csharp_service/[Unknown]" is denied.
at System.IO.FileStream.ReadData (System.Runtime.InteropServices.SafeHandle safeHandle, System.Byte[] buf, Int32 offset, Int32 count) <0x7fad47560300 + 0x000a3> in <filename unknown>:0
at System.IO.FileStream.ReadInternal (System.Byte[] dest, Int32 offset, Int32 count) <0x7fad4755e4a0 + 0x00076> in <filename unknown>:0
at System.IO.FileStream.Read (System.Byte[] array, Int32 offset, Int32 count) <0x7fad4755e2a0 + 0x000e1> in <filename unknown>:0
at System.IO.StreamReader.ReadBuffer () <0x7fad473cdb20 + 0x002a4> in <filename unknown>:0
at System.IO.StreamReader.ReadLine () <0x7fad473ce5e0 + 0x00068> in <filename unknown>:0
at System.IO.UnexceptionalStreamReader.ReadLine () <0x7fad47565f00 + 0x00018> in <filename unknown>:0
at System.IO.TextReader+SyncTextReader.ReadLine () <0x7fad473d3ae0 + 0x0001a> in <filename unknown>:0
at (wrapper synchronized) System.IO.TextReader+SyncTextReader:ReadLine ()
at System.Console.ReadLine () <0x7fad47660f50 + 0x00107> in <filename unknown>:0
at Sample.Main () <0x40585d50 + 0x000e1> in <filename unknown>:0
[ERROR] FATAL UNHANDLED EXCEPTION: System.UnauthorizedAccessException: Access to the path "/home/★user/shogi/csharp_service/[Unknown]" is denied.
at System.IO.FileStream.ReadData (System.Runtime.InteropServices.SafeHandle safeHandle, System.Byte[] buf, Int32 offset, Int32 count) <0x7fad47560300 + 0x000a3> in <filename unknown>:0
at System.IO.FileStream.ReadInternal (System.Byte[] dest, Int32 offset, Int32 count) <0x7fad4755e4a0 + 0x00076> in <filename unknown>:0
at System.IO.FileStream.Read (System.Byte[] array, Int32 offset, Int32 count) <0x7fad4755e2a0 + 0x000e1> in <filename unknown>:0
at System.IO.StreamReader.ReadBuffer () <0x7fad473cdb20 + 0x002a4> in <filename unknown>:0
at System.IO.StreamReader.ReadLine () <0x7fad473ce5e0 + 0x00068> in <filename unknown>:0
at System.IO.UnexceptionalStreamReader.ReadLine () <0x7fad47565f00 + 0x00018> in <filename unknown>:0
at System.IO.TextReader+SyncTextReader.ReadLine () <0x7fad473d3ae0 + 0x0001a> in <filename unknown>:0
at (wrapper synchronized) System.IO.TextReader+SyncTextReader:ReadLine ()
at System.Console.ReadLine () <0x7fad47660f50 + 0x00107> in <filename unknown>:0
at Sample.Main () <0x40585d50 + 0x000e1> in <filename unknown>:0
「ubuntu System.UnauthorizedAccessException #1186」(hbons/SparkleShare)
https://github.com/hbons/SparkleShare/issues/1186
フォルダーのパーミッションが問題だろうか?
# ls -l
drwxr-xr-x 3 root root 4096 Sep 12 2015 home
# ls -l
drwxr-xr-x 7 ★user ★user 4096 Mar 7 19:08 ★user
# ls -l
drwxr-xrwx 20 root root 4096 Mar 10 06:04 shogi
# ls -l
drwxr-xr-x 2 root root 4096 Mar 11 10:41 csharp_service
# ls -l
-rw-r--r-- 1 root root 2503 Mar 11 10:37 tamesi32a1_cs.err.log
-rwxr-xr-x 1 root root 3584 Mar 11 08:48 tamesi32a1_cs.exe
一般ユーザー・フォルダーの所有者だけ 一般ユーザーだが、
じゃあ、ルートユーザー・フォルダーに デプロイした方がいいのか?
# cd root
# ls
nohup.out tamesi32a1_cs.err.log tmp12
なんか ファイルができてる。
nano nohup.out
空っぽ。
nano tamesi32a1_cs.err.log
nohup: ignoring input and appending output to 'nohup.out'
nohup: failed to run command './tamesi32a1_cs.exe': No such file or directory
ここにディレクトリーを作ろう。
# mkdir shogi
# cd shogi
# mkdir csharp_service
# cd /home/★user/shogi/csharp_service
/home/★user/shogi/csharp_service# cp tamesi32a1_cs.exe /root/shogi/csharp_service/tamesi32a1_cs.exe
/home/★user/shogi/csharp_service# cp tamesi32a2_cs.exe /root/shogi/csharp_service/tamesi32a2_cs.exe
root@tk2-217-18401:~/shogi/csharp_service# nohup ./tamesi32a1_cs.exe 2> tamesi32a1_cs.err.log &
[1] 6050
root@tk2-217-18401:~/shogi/csharp_service# jobs
[1]+ Exit 1 nohup ./tamesi32a1_cs.exe 2> tamesi32a1_cs.err.log
root@tk2-217-18401:~/shogi/csharp_service# jobs
root@tk2-217-18401:~/shogi/csharp_service#
# nano tamesi32a1_cs.err.log
nohup: ignoring input and appending output to 'nohup.out'
Unhandled Exception:
System.UnauthorizedAccessException: Access to the path "/root/shogi/csharp_service/[Unknown]" is denied.
at System.IO.FileStream.ReadData (System.Runtime.InteropServices.SafeHandle safeHandle, System.Byte[] buf, Int32 offset, Int32 count) <0x7f1916560300 + 0x000a3> in <filename unknown>:0
at System.IO.FileStream.ReadInternal (System.Byte[] dest, Int32 offset, Int32 count) <0x7f191655e4a0 + 0x00076> in <filename unknown>:0
at System.IO.FileStream.Read (System.Byte[] array, Int32 offset, Int32 count) <0x7f191655e2a0 + 0x000e1> in <filename unknown>:0
at System.IO.StreamReader.ReadBuffer () <0x7f19163cdb20 + 0x002a4> in <filename unknown>:0
at System.IO.StreamReader.ReadLine () <0x7f19163ce5e0 + 0x00068> in <filename unknown>:0
at System.IO.UnexceptionalStreamReader.ReadLine () <0x7f1916565f00 + 0x00018> in <filename unknown>:0
at System.IO.TextReader+SyncTextReader.ReadLine () <0x7f19163d3ae0 + 0x0001a> in <filename unknown>:0
at (wrapper synchronized) System.IO.TextReader+SyncTextReader:ReadLine ()
at System.Console.ReadLine () <0x7f1916660f50 + 0x00107> in <filename unknown>:0
at Sample.Main () <0x41a97d50 + 0x000e1> in <filename unknown>:0
[ERROR] FATAL UNHANDLED EXCEPTION: System.UnauthorizedAccessException: Access to the path "/root/shogi/csharp_service/[Unknown]" is denied.
at System.IO.FileStream.ReadData (System.Runtime.InteropServices.SafeHandle safeHandle, System.Byte[] buf, Int32 offset, Int32 count) <0x7f1916560300 + 0x000a3> in <filename unknown>:0
at System.IO.FileStream.ReadInternal (System.Byte[] dest, Int32 offset, Int32 count) <0x7f191655e4a0 + 0x00076> in <filename unknown>:0
at System.IO.FileStream.Read (System.Byte[] array, Int32 offset, Int32 count) <0x7f191655e2a0 + 0x000e1> in <filename unknown>:0
at System.IO.StreamReader.ReadBuffer () <0x7f19163cdb20 + 0x002a4> in <filename unknown>:0
at System.IO.StreamReader.ReadLine () <0x7f19163ce5e0 + 0x00068> in <filename unknown>:0
at System.IO.UnexceptionalStreamReader.ReadLine () <0x7f1916565f00 + 0x00018> in <filename unknown>:0
at System.IO.TextReader+SyncTextReader.ReadLine () <0x7f19163d3ae0 + 0x0001a> in <filename unknown>:0
at (wrapper synchronized) System.IO.TextReader+SyncTextReader:ReadLine ()
at System.Console.ReadLine () <0x7f1916660f50 + 0x00107> in <filename unknown>:0
at Sample.Main () <0x41a97d50 + 0x000e1> in <filename unknown>:0
じゃあ、これでどうか?
# sudo nohup ./tamesi32a1_cs.exe 2> tamesi32a1_cs.err.log &
結果は同じ。
じゃあ逆に ルート権限でフォルダーを作ったのが悪いのではないか。
一般ユーザー権限でフォルダーを作るとどうなるか?
フォルダーの所有者を変えるには?
「【 所有者を変更する 】」(Linuxコマンド逆引き大全)
http://itpro.nikkeibp.co.jp/article/COLUMN/20060228/231047/
root@tk2-217-18401:/home/★user# chown ★user:★user shogi
こうか。
ディレクトリとファイルの所有者を変えていく。
# logout
★user@tk2-217-18401:~$ nohup ./tamesi32a1_cs.exe 2> tamesi32a1_cs.err.log &
[1] 6247
★user@tk2-217-18401:~$ jobs
[1]+ Exit 127 nohup ./tamesi32a1_cs.exe 2> tamesi32a1_cs.err.log
★user@tk2-217-18401:~$ jobs
とほほ。
$ nano tamesi32a1_cs.err.log
nohup: ignoring input and appending output to 'nohup.out'
nohup: failed to run command './tamesi32a1_cs.exe': No such file or directory
あれ、現在いるディレクトリが 思っている場所と違う。logout した影響か。
だから 初心者に教えるときは 絶対パスをやらせてみるのがいいのか。
~/shogi/csharp_service$ nohup /home/★user/shogi/csharp_service/tamesi32a1_cs.exe 2> /home/★user/shogi/csharp_service/tamesi32a1_cs.err.log &
[1] 6326
★user@tk2-217-18401:~/shogi/csharp_service$ jobs
[1]+ Exit 1 nohup /home/★user/shogi/csharp_service/tamesi32a1_cs.exe 2> /home/★user/shogi/csharp_service/tamesi32a1_cs.err.log
★user@tk2-217-18401:~/shogi/csharp_service$ jobs
★user@tk2-217-18401:~/shogi/csharp_service$
$ nano tamesi32a1_cs.err.log
nohup: ignoring input and appending output to '/home/★user/nohup.out'
Unhandled Exception:
System.UnauthorizedAccessException: Access to the path "/home/★user/shogi/csharp_service/[Unknown]" is denied.
at System.IO.FileStream.ReadData (System.Runtime.InteropServices.SafeHandle safeHandle, System.Byte[] buf, Int32 offset, Int32 count) <0x7f9fd3960300 + 0x000a3> in <filename unknown>:0
at System.IO.FileStream.ReadInternal (System.Byte[] dest, Int32 offset, Int32 count) <0x7f9fd395e4a0 + 0x00076> in <filename unknown>:0
at System.IO.FileStream.Read (System.Byte[] array, Int32 offset, Int32 count) <0x7f9fd395e2a0 + 0x000e1> in <filename unknown>:0
at System.IO.StreamReader.ReadBuffer () <0x7f9fd37cdb20 + 0x002a4> in <filename unknown>:0
at System.IO.StreamReader.ReadLine () <0x7f9fd37ce5e0 + 0x00068> in <filename unknown>:0
at System.IO.UnexceptionalStreamReader.ReadLine () <0x7f9fd3965f00 + 0x00018> in <filename unknown>:0
at System.IO.TextReader+SyncTextReader.ReadLine () <0x7f9fd37d3ae0 + 0x0001a> in <filename unknown>:0
at (wrapper synchronized) System.IO.TextReader+SyncTextReader:ReadLine ()
at System.Console.ReadLine () <0x7f9fd3a60f50 + 0x00107> in <filename unknown>:0
at Sample.Main () <0x404aad50 + 0x000e1> in <filename unknown>:0
[ERROR] FATAL UNHANDLED EXCEPTION: System.UnauthorizedAccessException: Access to the path "/home/★user/shogi/csharp_service/[Unknown]" is denied.
at System.IO.FileStream.ReadData (System.Runtime.InteropServices.SafeHandle safeHandle, System.Byte[] buf, Int32 offset, Int32 count) <0x7f9fd3960300 + 0x000a3> in <filename unknown>:0
at System.IO.FileStream.ReadInternal (System.Byte[] dest, Int32 offset, Int32 count) <0x7f9fd395e4a0 + 0x00076> in <filename unknown>:0
at System.IO.FileStream.Read (System.Byte[] array, Int32 offset, Int32 count) <0x7f9fd395e2a0 + 0x000e1> in <filename unknown>:0
at System.IO.StreamReader.ReadBuffer () <0x7f9fd37cdb20 + 0x002a4> in <filename unknown>:0
at System.IO.StreamReader.ReadLine () <0x7f9fd37ce5e0 + 0x00068> in <filename unknown>:0
at System.IO.UnexceptionalStreamReader.ReadLine () <0x7f9fd3965f00 + 0x00018> in <filename unknown>:0
at System.IO.TextReader+SyncTextReader.ReadLine () <0x7f9fd37d3ae0 + 0x0001a> in <filename unknown>:0
at (wrapper synchronized) System.IO.TextReader+SyncTextReader:ReadLine ()
at System.Console.ReadLine () <0x7f9fd3a60f50 + 0x00107> in <filename unknown>:0
at Sample.Main () <0x404aad50 + 0x000e1> in <filename unknown>:0
おんなじエラーだろう。
$ nohup ~/shogi/csharp_service/tamesi32a1_cs.exe 2> ~/shogi/csharp_service/tamesi32a1_cs.err.log &
こんな書き方をしても コマンドは通るみたいだが結果は同じ。
$ chmod 777 csharp_service
一般ユーザーでもこんな権限あるのか。
でも変わり無し。
at (wrapper synchronized) System.IO.TextReader+SyncTextReader:ReadLine ()
at System.Console.ReadLine () <0x7f3cd3260f50 + 0x00107> in <filename unknown>:0
at Sample.Main () <0x4113cd50 + 0x000e1> in <filename unknown>:0
エラーログを読んでみると System.Console.ReadLine () が原因のようだが、標準入力を無視して '/home/csg10/nohup.out' を追加していることと関係あるんだろうか。
$ ps axjf
へー。ツリー構造にもなるのか。
~$ ls -l
total 8
-rw------- 1 csg10 csg10 164 Mar 11 11:12 nohup.out
drwxrwxrwx 20 csg10 csg10 4096 Mar 11 11:08 shogi
nohup.out のパーミッションを変えてみるか。
$ chmod 777 nohup.out
$ ls -l
total 8
-rwxrwxrwx 1 csg10 csg10 164 Mar 11 11:12 nohup.out
drwxrwxrwx 20 csg10 csg10 4096 Mar 11 11:08 shogi
権限のないアクセスをしたという例外なのか。
じゃあむしろ 実行ファイルには ルート権限が付いていた方がいいのか?
# chown root:root tamesi32a1_cs.exe
# chown root:root tamesi32a2_cs.exe
変わり無し。
daemon はどうやるのか?
むずかしそう。パス。
標準入出力か、ReadLine( ) が悪いのでは? 全部 TCP でできないか?
調べてみるか。