LoginSignup
0
1

More than 5 years have passed since last update.

コンピュータ将棋ソフトとの対局サーバーを立てよう<その7>

Last updated at Posted at 2017-03-10

なんか 意識がホワイトアウトするんだが まあいいだろう。

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 でできないか?

調べてみるか。

長くなったので記事を変える。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1