コンピュータ将棋ソフトとの対局サーバーを立てよう＜その２＞

前回の記事: 「＜その１＞」 http://qiita.com/muzudho1/items/af3537d36f16c063a572

# Ubuntuでプロセス間通信しよう

エラーが出る……、RabbitMQっていったい何メッセージ・キューだ？ 

(RabbitMQ)
https://www.rabbitmq.com/

「RabbitMQ Configuration」 (RabbitMQ)
https://www.rabbitmq.com/configure.html

設定ファイル

```
node           : rabbit@example
home dir       : /var/lib/rabbitmq
config file(s) : /etc/rabbitmq/rabbitmq.config
```

ログファイル

```
node           : rabbit@example
home dir       : /var/lib/rabbitmq
config file(s) : /var/lib/rabbitmq/hare.config (not found)
```

うーむ、broker という単語も出てくるがよくわからない。
トラブル・シューティングのページは無いものか。

「Introduction」 (RabbitMQ)
https://www.rabbitmq.com/tutorials/tutorial-one-dotnet.html

公式のサンプル・プログラムを見ると、わたしの知ってるサンプル・プログラムよりも難しいことをしている。

RabbitMQ.Client.dll というライブラリは サーバーの中にあるのだろうか。どうやって調べるんだろうか？

「特定のファイルが含まれるパッケージを探す」 (Qiita)
http://qiita.com/Yuichirou/items/38165af29ab1e2d307f6

じゃあ

```
apt-file search RabbitMQ.Client.dll
```

みたいな感じでいいんだろうか？

```
The program 'apt-file' is currently not installed. You can install it by typing:
apt install apt-file
```

じゃあまず、インストールから。

```
apt install apt-file
～中略～
The system-wide cache is empty. You may want to run 'apt-file update'
as root to update the cache. You can also run 'apt-file update' as
normal user to use a cache in the user's home directory.
```

じゃあ次、アップデート。

```
apt-file update
～中略～

File is up-to-date.
```

じゃあまた検索。

```
apt-file search RabbitMQ.Client.dll
libmono-rabbitmq4.0-cil: /usr/lib/mono/4.5/RabbitMQ.Client.dll
libmono-rabbitmq4.0-cil: /usr/lib/mono/gac/RabbitMQ.Client/4.0.0.0__b03f5f7f11d50a3a/RabbitMQ.Client.dll
mono-dbg: /usr/lib/mono/gac/RabbitMQ.Client/4.0.0.0__b03f5f7f11d50a3a/RabbitMQ.Client.dll.mdb
mono-reference-assemblies-2.0: /usr/lib/mono/2.0/RabbitMQ.Client.dll
mono-reference-assemblies-4.0: /usr/lib/mono/4.0/RabbitMQ.Client.dll
```

ほうほう、RabbitMQ.Client.dll は入ってるぜ。

ファクトリーを作って、コネクションを確立して、チャンネルを開け、と書いてあるな。
サンプル・プログラムを書いてみるか。

続く。

System.Messaging ネームスペースを使ってると RabbitQL は見えないようにしているんじゃないか。

```
nano MsgQueue.cs
mcs /reference:System.Messaging.dll MsgQueue.cs
 ./MsgQueue.exe
選べだぜ☆（＾～＾）
1   : メッセージ箱 作成
2   : メッセージ   送信
3   : メッセージ   受信
4   : メッセージ箱 削除
quit: 終了

1
mq.BasePriority = 0

Unhandled Exception:
System.NotImplementedException: The method or operation is not implemented.
  at Mono.Messaging.RabbitMQ.RabbitMQMessageQueue.get_CanRead () <0x408d0100 + 0x00017> in <filename unknown>:0
  at System.Messaging.MessageQueue.get_CanRead () <0x408d0090 + 0x00020> in <filename unknown>:0
  at (wrapper remoting-invoke-with-check) System.Messaging.MessageQueue:get_CanRead ()
  at MsgQueue.Program.Main (System.String[] args) <0x4089dd50 + 0x001ff> in <filename unknown>:0
[ERROR] FATAL UNHANDLED EXCEPTION: System.NotImplementedException: The method or operation is not implemented.
  at Mono.Messaging.RabbitMQ.RabbitMQMessageQueue.get_CanRead () <0x408d0100 + 0x00017> in <filename unknown>:0
  at System.Messaging.MessageQueue.get_CanRead () <0x408d0090 + 0x00020> in <filename unknown>:0
  at (wrapper remoting-invoke-with-check) System.Messaging.MessageQueue:get_CanRead ()
  at MsgQueue.Program.Main (System.String[] args) <0x4089dd50 + 0x001ff> in <filename unknown>:0
```

ありゃ、CanRead プロパティー使えないのか。コンパイル通ってるのに、なんで使えないんだ？

Windows だと

```
mq.AccessMode = SendAndReceive
mq.Authenticate = False
mq.BasePriority = 0
mq.CanRead = True
mq.CanWrite = True
mq.Category = 00000000-0000-0000-0000-000000000000
mq.Container =
mq.CreateTime = 2017/03/06 18:13:13
mq.DefaultPropertiesToSend = System.Messaging.DefaultPropertiesToSend
mq.DenySharedReceive = False
mq.EncryptionRequired = Optional
mq.FormatName = DIRECT=OS:takahashi-pc\Private$\testqueue
mq.Formatter = System.Messaging.XmlMessageFormatter
mq.Id = 00000000-0000-0000-0000-000000000000
mq.Label =
mq.LastModifyTime = 2017/03/06 18:13:13
mq.MachineName = .
mq.MaximumJournalSize = 4294967295
mq.MaximumQueueSize = 4294967295
mq.MessageReadPropertyFilter = System.Messaging.MessagePropertyFilter
mq.MulticastAddress =
mq.Path = .\Private$\testqueue
mq.QueueName = Private$\testqueue
mq.ReadHandle = 1788
mq.Site =
mq.SynchronizingObject =
mq.Transactional = False
mq.UseJournalQueue = False
mq.WriteHandle = 1588
```

こんな感じでプロパティは読めるので、実装がないとしたら　実際　未実装なのか。
インストールとかできないのか？

# RabbitMQ を入手した方がいいのでは？

System.Messaging を使ってるのが間違いなのか？

「How do I use RabbitMQ on Mono on Linux」 (stack overflow)
http://stackoverflow.com/questions/28020761/how-do-i-use-rabbitmq-on-mono-on-linux

# Erlang （アーラン）をダウンロードしよう

RabbitMQをインストールする前に、Erlang をインストールしてくれって出てきた。

「DOWNLOAD OTP 19.2」 (ERLANG)
http://www.erlang.org/downloads

じゃあ、Windows 64bit 用バイナリをダウンロードするか。

えっ！　ダウンロードまで 2時間 1時間 2時間 40分……、なんだろう、どんな細い回線を通ってダウンロードされてくるんだろう。

自宅の回線が細くなったんじゃないか。その間に他の作業からやろう。

# PHP と メッセージ・キューは通信できるのか？

## メッセージ・キューには次のものがあるはずだ

- キューの既存確認
- キューの作成
- キューへ送信
- キューから受信
- キューの削除

PHP ではどれに当てはまるだろう？

- キューの作成または取得 msg_get_queue()
- キューへ送信 msg_send()
- キューから受信 msg_receive()
- キューの削除 msg_remove_queue()
- msg_set_queue() メッセージの設定
- msg_stat_queue() メッセージの取得

それぞれ調べてみよう。

「msg_get_queue」 (PHPマニュアル)
http://php.net/manual/ja/function.msg-get-queue.php

```
$MSGKey = "123456" ; 

## Create or attach to a message queue
$seg = msg_get_queue($MSGKey) ;
```

メッセージのキーが数字というのはどういうことだろう。/Private$/testqueue みたいな文字列じゃないならどうやって C# と PHP で同じキューを見にいくんだろう。


「RabbitMQ + php-amqplib でメッセージキューイング試してみた」 (Qiita)
http://qiita.com/imunew/items/d93917c0344f5ef1abce

「新人プログラマに知ってもらいたいRabbitMQ初心者の入門の入門」 (Qiita)
http://qiita.com/gambaray/items/3cc02b419c860a96bc94

「RabbitMQ の導入」 (Qiita)
http://qiita.com/taka1970/items/fa783304b7a71b7921e5

# Linuxの環境変数？

「System.Messaging」 (Mono)
http://www.mono-project.com/archived/systemmessaging/

Linux で System.Messaging を使おうと思ったら、環境変数を定義する必要があるんだろうか？

それとも Windowsの話しだろうか。

# ERLANG をダウンロードしたぞ

Windows 上に RabbitMQ + ERLANG の環境を構築したい。ローカルテスト用に。
ダウンロードしてきたERLANGの .exe を叩いてインストールした。次は RabbitMQ か。

RabbitMQ のインストールを進める。ファイアウォールに２回ブロックされてるが許可して進めた。

じゃあ C# で

```
using RabbitMQ.Client;
```

とか使えるようになったんだろうか？　調べてみよう。

そんな様子はどこにもなく。

# RabbitMQ.Client.dll を探すか

C:\Program Files\RabbitMQ Server フォルダーの中には無い。
というか Unity が持っている。

正規的には、どこから入手するんだろうか。

「.NET/C# RabbitMQ client library」 (RabbitMQ)
https://www.rabbitmq.com/dotnet.html

# NuGetパッケージ

NuGetパッケージを使ってインストールしてください、とあるが NuGetパッケージとは何か。

「RabbitMQ .NETクライアント 4.1.1」 (nuget)
https://www.nuget.org/packages/RabbitMQ.Client

## パッケージマネージャコンソールって何だ？

「パッケージマネージャコンソール」 (Microsoft)
https://docs.microsoft.com/ja-jp/nuget/tools/package-manager-console

Visual Studio 2015 を使っていて今まで気づかなかったが、
メインメニューから [Tools] - [NuGet Package Manager] - [Package Manager Console] と進める。

すると　いつも　エラーとか検索結果が出ていたペインに Package Manager Console が出てきて入力を促している。

```
PM>
```

じゃあ、入力してみる。

```
PM> Install-Package RabbitMQ.Client -Version 4.1.1
Attempting to gather dependencies information for package 'RabbitMQ.Client.4.1.1' with respect to project 'UsagiMQ', targeting '.NETFramework,Version=v4.5.2'
Attempting to resolve dependencies for package 'RabbitMQ.Client.4.1.1' with DependencyBehavior 'Lowest'
Resolving actions to install package 'RabbitMQ.Client.4.1.1'
Resolved actions to install package 'RabbitMQ.Client.4.1.1'
Adding package 'RabbitMQ.Client.4.1.1' to folder 'C:\Users\Takahashi\Documents\muzudho\Shogi_Ubuntu\UsagiMQ\packages'
Added package 'RabbitMQ.Client.4.1.1' to folder 'C:\Users\Takahashi\Documents\muzudho\Shogi_Ubuntu\UsagiMQ\packages'
Added package 'RabbitMQ.Client.4.1.1' to 'packages.config'
Successfully installed 'RabbitMQ.Client 4.1.1' to UsagiMQ
```

**おーっ！**

じゃあ今どきは　ホームページからファイルをダウンロードするより、NuGet を使ってファイルをダウンロードした方がいいのか。

すると、C# 言語で

```
using RabbitMQ.Client;
```

と書いてもエラーにならなくなった。

# RabbitMQ のサンプル・プログラムを書いてみよう。

「Introduction」 (RabbitMQ)
https://www.rabbitmq.com/tutorials/tutorial-one-dotnet.html

サンプルプログラムをコピペ実行すると 文字のやりとりをやってるみたいなんだが、
前回の記事みたいに「コンピューターの管理」からいける「メッセージ キュー」の中にはなんにも入ってないようで、送信と受信の２つがないと　ちゃんと　やりとりしてるのかテストできないんだな。

じゃあ、これ別に２つのプログラムにしなくても　１つのプログラムにまとめられそうなので、まとめてみるか。

長くなったが、これでいけた。

```C#
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Text;

namespace UsagiMQ
{
    class Program
    {
        public const string
            HOST_NAME = "localhost",
            QUEUE_NAME = "hello";

        static void Main(string[] args)
        {
            for (;;)
            {
                Console.WriteLine(@"選べだぜ☆（＾～＾）
1   : メッセージ   送信
2   : メッセージ   受信
quit: 終了
");

                int category = 0;
                for (;;)
                {
                    string line = Console.ReadLine();
                    switch (line)
                    {
                        case "1": category = 1; goto gt_EndLoop1;
                        case "2": category = 2; 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();
                            Send(line);
                        }
                        break;
                    case 2: Receive(); break;
                }
            }
            gt_Quit:
            ;
        }

        static void Send(string message)
        {
            var factory = new ConnectionFactory() { HostName = HOST_NAME };
            using (var connection = factory.CreateConnection())
            {
                using (var channel = connection.CreateModel())
                {
                    channel.QueueDeclare(queue: QUEUE_NAME,
                                         durable: false,
                                         exclusive: false,
                                         autoDelete: false,
                                         arguments: null);

                    var body = Encoding.UTF8.GetBytes(message);

                    channel.BasicPublish(exchange: "",
                                         routingKey: QUEUE_NAME,
                                         basicProperties: null,
                                         body: body);
                    Console.WriteLine(" Sent(^q^) {0}", message);
                }
            }

            Console.WriteLine(" Press [enter] to menu.");
            Console.ReadLine();
        }

        static void Receive()
        {
            var factory = new ConnectionFactory() { HostName = HOST_NAME };
            using (var connection = factory.CreateConnection())
            {
                using (var channel = connection.CreateModel())
                {
                    channel.QueueDeclare(queue: QUEUE_NAME,
                                         durable: false,
                                         exclusive: false,
                                         autoDelete: false,
                                         arguments: null);

                    var consumer = new EventingBasicConsumer(channel);
                    // 受信できたときに割り込んでくる処理
                    consumer.Received += (model, ea) =>
                    {
                        var body = ea.Body;
                        var message = Encoding.UTF8.GetString(body);
                        Console.WriteLine(" [interrupt!] Received(^q^) {0}", message);
                    };
                    channel.BasicConsume(queue: QUEUE_NAME,
                                         noAck: true,
                                         consumer: consumer);

                    Console.WriteLine(" Please, wait receiving... Or Press [enter] to menu.");
                    Console.ReadLine();
                }
            }
        }

    }
}
```

これ、Ubuntuでコンパイルできるんだろうか？　やってみよう。

じゃあ、前に書いたプログラムは捨てるぜ。

```
rm MsgQueue.cs
nano MsgQueue.cs
```

```
mcs MsgQueue.cs
MsgQueue.cs(1,7): error CS0246: The type or namespace name `RabbitMQ' could not be found. Are you missing an assembly reference?
MsgQueue.cs(2,7): error CS0246: The type or namespace name `RabbitMQ' could not be found. Are you missing an assembly reference?
Compilation failed: 2 error(s), 0 warnings
```

じゃあ、こうか。

```
mcs /reference:RabbitMQ.Client.dll MsgQueue.cs
mcs /reference:RabbitMQ.C             lient.dll MsgQueue.cs
MsgQueue.cs(63,29): error CS1501: No overload for method `QueueDeclare' takes `5             ' arguments
/usr/lib/mono/4.5/RabbitMQ.Client.dll (Location of the symbol related to previou             s error)
MsgQueue.cs(90,29): error CS1501: No overload for method `QueueDeclare' takes `5             ' arguments
/usr/lib/mono/4.5/RabbitMQ.Client.dll (Location of the symbol related to previou             s error)
MsgQueue.cs(96,36): error CS1729: The type `RabbitMQ.Client.Events.EventingBasic             Consumer' does not contain a constructor that takes `1' arguments
/usr/lib/mono/4.5/RabbitMQ.Client.dll (Location of the symbol related to previou             s error)
MsgQueue.cs(105,42): error CS1739: The best overloaded method match for `RabbitM             Q.Client.IModel.BasicConsume(string, System.Collections.IDictionary, RabbitMQ.Cl             ient.IBasicConsumer)' does not contain a parameter named `noAck'
/usr/lib/mono/4.5/RabbitMQ.Client.dll (Location of the symbol related to previou             s error)
MsgQueue.cs(104,29): error CS1502: The best overloaded method match for `RabbitM             Q.Client.IModel.BasicConsume(string, System.Collections.IDictionary, RabbitMQ.Cl             ient.IBasicConsumer)' has some invalid arguments
/usr/lib/mono/4.5/RabbitMQ.Client.dll (Location of the symbol related to previou             s error)
MsgQueue.cs(105,49): error CS1503: Argument `#2' cannot convert `bool' expressio             n to type `System.Collections.IDictionary'
Compilation failed: 6 error(s), 0 warnings
```

なんか RabbitMQ.Client.dll のバージョンとか古いという話しだろうか。

# RabbitMQ.Client.dll のアップグレードの方法を調べてみよう。

「Installing on Debian / Ubuntu」 (RabbitMQ)
https://www.rabbitmq.com/install-debian.html

なんだか分からんが　書かれているコマンド打っていこう。

```
echo 'deb http://www.rabbitmq.com/debian/ testing main' | sudo tee /etc/apt/sources.list.d/rabbitmq.list
deb http://www.rabbitmq.com/debian/ testing main
```

なんか URL のようなものが出てきた。

```
sudo apt-get update
```

なんか動いたが、うまくいったのか、何も起こらなかったのか、エラーなのかなんなのか　わからん。

```
sudo apt-get install rabbitmq-server
```

なんか進んで終わった。

なんか追加するらしい。

```
gpg --keyserver pgpkeys.mit.edu --recv-key 7638D0442B90D010
```

```
gpg -a --export 7638D0442B90D010 | sudo apt-key add -
OK
```

```
echo 'deb http://ftp.debian.org/debian wheezy-backports main' | sudo tee /etc/apt/sources.list.d/wheezy_backports.list
deb http://ftp.debian.org/debian wheezy-backports main
```

まだなんか追加するらしい。

```
wget -O- https://packages.erlang-solutions.com/debian/erlang_solutions.asc | sudo apt-key add -
OK
```

```
echo 'deb https://packages.erlang-solutions.com/debian wheezy contrib' | sudo tee /etc/apt/sources.list.d/esl.list
deb https://packages.erlang-solutions.com/debian wheezy contrib
```

アップグレードだ。

```
sudo apt-get update
```

```
sudo apt-get install init-system-helpers socat esl-erlang
```

なんかいっぱいインストールされた。次は RabbitMQ の何か。

```
wget -O- https://www.rabbitmq.com/rabbitmq-release-signing-key.asc | sudo apt-key add -
OK
```

```
echo 'deb http://www.rabbitmq.com/debian/ testing main' | sudo tee /etc/apt/sources.list.d/rabbitmq.list
deb http://www.rabbitmq.com/debian/ testing main
```

```
sudo apt-get update
```

```
sudo apt-get install rabbitmq-server
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
```

これでいいのだろうか？

```
mcs /reference:RabbitMQ.Client.dll MsgQueue.cs
MsgQueue.cs(63,29): error CS1501: No overload for method `QueueDeclare' takes `5' arguments
/usr/lib/mono/4.5/RabbitMQ.Client.dll (Location of the symbol related to previous error)
MsgQueue.cs(90,29): error CS1501: No overload for method `QueueDeclare' takes `5' arguments
/usr/lib/mono/4.5/RabbitMQ.Client.dll (Location of the symbol related to previous error)
MsgQueue.cs(96,36): error CS1729: The type `RabbitMQ.Client.Events.EventingBasicConsumer' does not contain a constructor that takes `1' arguments
/usr/lib/mono/4.5/RabbitMQ.Client.dll (Location of the symbol related to previous error)
MsgQueue.cs(105,42): error CS1739: The best overloaded method match for `RabbitMQ.Client.IModel.BasicConsume(string, System.Collections.IDictionary, RabbitMQ.Client.IBasicConsumer)' does not contain a parameter named `noAck'
/usr/lib/mono/4.5/RabbitMQ.Client.dll (Location of the symbol related to previous error)
MsgQueue.cs(104,29): error CS1502: The best overloaded method match for `RabbitMQ.Client.IModel.BasicConsume(string, System.Collections.IDictionary, RabbitMQ.Client.IBasicConsumer)' has some invalid arguments
/usr/lib/mono/4.5/RabbitMQ.Client.dll (Location of the symbol related to previous error)
MsgQueue.cs(105,49): error CS1503: Argument `#2' cannot convert `bool' expression to type `System.Collections.IDictionary'
Compilation failed: 6 error(s), 0 warnings
```

うーん、引数が5個のQueueDeclareメソッドが無いとか、何だ。

# サンプル・プログラムでは引数が５個

「Error: “No OverLoad For Method 'ExecuteInsert' takes '5' argument” [closed]」 (stack overflow)
http://stackoverflow.com/questions/14638880/error-no-overload-for-method-executeinsert-takes-5-argument

じゃあ、Windows 10 では問題なく動くサンプル・プログラムのここがダメなのか？

```
                    channel.QueueDeclare(queue: QUEUE_NAME,
                                         durable: false,
                                         exclusive: false,
                                         autoDelete: false,
                                         arguments: null);
```

じゃあ　どうすればいいのか……。
エラーの別の部分も見てみよう。

```
RabbitMQ.Client.dll (Location of the symbol related to previous error)
```

```
mono -V
Mono JIT compiler version 4.2.1 (Debian 4.2.1.102+dfsg2-7ubuntu4)
Copyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com
        TLS:           __thread
        SIGSEGV:       altstack
        Notifications: epoll
        Architecture:  amd64
        Disabled:      none
        Misc:          softdebug
        LLVM:          supported, not enabled.
        GC:            sgen
```

# Ubuntu で NuGet って使えるの？

「Introduction」 (RabbitMQ)
https://www.rabbitmq.com/tutorials/tutorial-one-dotnet.html

C#コンパイラには mcs を使っていたが、csc の方がいいんだろうか？

「mcsの最新情報と今後の展望について」 (ものがたり)
http://atsushieno.hatenablog.com/entry/2014/12/11/000240

csc がマイクロソフトのC#コンパイラで、
mcs がmono のC#コンパイラだろうか。

Ubuntuにcsc を入れれるだろうか。

「UbuntuServerに、Mono環境を構築する」 (Qiita)
http://qiita.com/takanemu/items/52888d324df3d367d4c1

mono-csc というコマンドがあるんだろうか？

```
mono-csc /r:"RabbitMQ.Client.dll" MsgQueue.cs
MsgQueue.cs(61,21): error CS1501: No overload for method `QueueDeclare' takes `5' arguments
/usr/lib/mono/4.5/RabbitMQ.Client.dll (Location of the symbol related to previous error)
MsgQueue.cs(76,21): error CS1501: No overload for method `QueueDeclare' takes `5' arguments
/usr/lib/mono/4.5/RabbitMQ.Client.dll (Location of the symbol related to previous error)
MsgQueue.cs(78,46): error CS1729: The type `RabbitMQ.Client.Events.EventingBasicConsumer' does not contain a constructor that takes `1' arguments
/usr/lib/mono/4.5/RabbitMQ.Client.dll (Location of the symbol related to previous error)
MsgQueue.cs(86,21): error CS1502: The best overloaded method match for `RabbitMQ.Client.IModel.BasicConsume(string, System.Collections.IDictionary, RabbitMQ.Client.IBasicConsumer)' has some invalid arguments
/usr/lib/mono/4.5/RabbitMQ.Client.dll (Location of the symbol related to previous error)
MsgQueue.cs(86,46): error CS1503: Argument `#2' cannot convert `bool' expression to type `System.Collections.IDictionary'
Compilation failed: 5 error(s), 0 warnings
```

あるようだがエラーだ。 QueueDeclare の仕様はどうなっているのか？

「QueueDeclare(String,Boolean,Boolean,Boolean,Boolean,Boolean,IDictionary) Method」 (http://docs.spring.io)
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

Ubuntuの RabbitMQ が古いバージョンなんだろうか。さっきアップグレードしたと思うんだが。

# RabbitMQ の停止と起動

「RabbitMQを試してみる」 (shinodogg.com)
https://shinodogg.com/?p=4641

```
rabbitmqctl stop
Stopping and halting node 'rabbit@tk2-217-18401' ...
Error: unable to connect to node ～以下略～
```

停止しようとしたらエラーが出た。

```
 rabbitmq-server

              RabbitMQ 3.6.6. Copyright (C) 2007-2016 Pivotal Software, Inc.
  ##  ##      Licensed under the MPL.  See http://www.rabbitmq.com/
  ##  ##
  ##########  Logs: /var/log/rabbitmq/～略～
  ######  ##        /var/log/rabbitmq/～略～
  ##########
              Starting broker...
 completed with 0 plugins.
```

起動はうまくいったんだろうか？

[Ctrl]+[Z] で止めて

```
[1]+  Stopped                 rabbitmq-server
```

```
bg 1
[1]+ rabbitmq-server &
```

して、

```
mcs /r:"RabbitMQ.Client.dll" MsgQueue.cs
MsgQueue.cs(61,21): error CS1501: No overload for method `QueueDeclare' takes `5' arguments
/usr/lib/mono/4.5/RabbitMQ.Client.dll (Location of the symbol related to previous error)
MsgQueue.cs(76,21): error CS1501: No overload for method `QueueDeclare' takes `5' arguments
/usr/lib/mono/4.5/RabbitMQ.Client.dll (Location of the symbol related to previous error)
MsgQueue.cs(78,46): error CS1729: The type `RabbitMQ.Client.Events.EventingBasicConsumer' does not contain a constructor that takes `1' arguments
/usr/lib/mono/4.5/RabbitMQ.Client.dll (Location of the symbol related to previous error)
MsgQueue.cs(86,21): error CS1502: The best overloaded method match for `RabbitMQ.Client.IModel.BasicConsume(string, System.Collections.IDictionary, RabbitMQ.Client.IBasicConsumer)' has some invalid arguments
/usr/lib/mono/4.5/RabbitMQ.Client.dll (Location of the symbol related to previous error)
MsgQueue.cs(86,46): error CS1503: Argument `#2' cannot convert `bool' expression to type `System.Collections.IDictionary'
Compilation failed: 5 error(s), 0 warnings
```

関係無いのか。

「[RabbitMQ]RabbitMQをUbuntuにインストールしてサンプルと管理画面を動かしてみる」 (ズッキーニのプログラミング実験場)
http://zuqqhi2.com/install-rabbitmq

```
sudo /etc/init.d/rabbitmq-server status
● rabbitmq-server.service - RabbitMQ broker
   Loaded: loaded (/lib/systemd/system/rabbitmq-server.service; enabled; vendor preset: enabled)
   Active: inactive (dead) since Mon 2017-03-06 21:27:42 JST; 1h 16min ago
 Main PID: 23830 (code=killed, signal=TERM)
   Status: "Exited."

Mar 06 21:20:39 tk2-217-18401 rabbitmq-server[23830]:   ######  ##        /var/log/rabbitmq/★～略～.log
Mar 06 21:20:39 tk2-217-18401 rabbitmq-server[23830]:   ##########
Mar 06 21:20:39 tk2-217-18401 rabbitmq-server[23830]:               Starting broker...
Mar 06 21:20:41 tk2-217-18401 rabbitmq-server[23830]: systemd unit for activation check: "rabbitmq-server.service"
Mar 06 21:20:41 tk2-217-18401 systemd[1]: Started RabbitMQ broker.
Mar 06 21:20:42 tk2-217-18401 rabbitmq-server[23830]:  completed with 0 plugins.
Mar 06 21:27:40 tk2-217-18401 systemd[1]: Stopping RabbitMQ broker...
Mar 06 21:27:42 tk2-217-18401 rabbitmqctl[24821]: Stopping and halting node 'rabbit@★～略～' ...
Mar 06 21:27:42 tk2-217-18401 rabbitmq-server[23830]: Gracefully halting Erlang VM
Mar 06 21:27:42 tk2-217-18401 systemd[1]: Stopped RabbitMQ broker.
```

さっぱりわからん。

「Vagrant上のUbuntuにRabbitMQをたててMQTTをお試し」 (braitom's Tech Memo)
http://braitom.hatenablog.com/entry/2015/05/16/004515

```
sudo /etc/init.d/rabbitmq-server restart
[....] Restarting rabbitmq-server (via systemctl): rabbitmq-server.serviceGracefully halting Erlang VM
Job for rabbitmq-server.service failed because the control process exited with error code. See "systemctl status rabbitmq-server.service" and "journalctl -xe" for details.
 failed!
```

これもよくわからんがエラー。

# プロセス間通信以外の方法があるだろうか？

接続の確立だけやろうとしたら

```
System.Net.Sockets.SocketException: Connection refused
```

だし、

```
sudo rabbitmq-server
```

を打ち込むと止まってしまう。ただ、[Ctrl]+[Z] から

```
bg 1
```

として再度

```
./MsgQueue.exe
```

とすると、接続の確立まではいけるようだ。

# じゃあ、 QueueDeclare の引数はいくつだったらいいのか？

別の解法を探す時間と、わたしのバグ探し能力で押し通すのとどっちが速いだろうか。
じゃあ 試しに 7個の引数でやってみよう。

```
root@tk2-217-18401:/home/csg10/shogi/ukamuse_sdt4/bin# nano MsgQueue.cs
root@tk2-217-18401:/home/csg10/shogi/ukamuse_sdt4/bin# mcs /r:"RabbitMQ.Client.dll" MsgQueue.cs
MsgQueue.cs(64,21): error CS1502: The best overloaded method match for `RabbitMQ.Client.IModel.QueueDeclare(string, bool, bool, bool, bool, bool, System.Collections.IDictionary)' has some invalid arguments
/usr/lib/mono/4.5/RabbitMQ.Client.dll (Location of the symbol related to previous error)
MsgQueue.cs(64,67): error CS1503: Argument `#5' cannot convert `null' expression to type `bool'
Compilation failed: 2 error(s), 0 warnings
```

関数のプロトタイプがでてきてくれた。引数は、

- string
- bool
- bool
- bool
- bool
- bool
- System.Collections.IDictionary

のようだ。これは　いつのバージョンの QueueDeclare なんだろうか？

ネット上に落ちている Spring.Messaging.Amqp.Rabbit では、

「QueueDeclare(String,Boolean,Boolean,Boolean,Boolean,Boolean,IDictionary) Method」 (http://docs.spring.io)
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

```
public string QueueDeclare( 
   string queue,
   bool passive,
   bool durable,
   bool exclusive,
   bool autoDelete,
   bool nowait,
   IDictionary arguments
)
```

で、RabbitMQ では

```
channel.QueueDeclare(queue: "hello",
                                 durable: false,
                                 exclusive: false,
                                 autoDelete: false,
                                 arguments: null);
```

なので、どういうことなのか。第2引数 passive と 第6引数 nowait に適当に false でも入れておけばいいのか？

```
nano MsgQueue.cs
mcs /r:"RabbitMQ.Client.dll" MsgQueue.cs
```

引数７つにしたら　コンパイルは通った。
引数の数が異なるメソッドはまだある。

```
EventingBasicConsumer consumer = new EventingBasicConsumer(channel);
```

このコンストラクタ。引数が１つではないらしいのだ。じゃあ null でも追加して引数を２つにしてみる。

```
mcs /r:"RabbitMQ.Client.dll" MsgQueue.cs
MsgQueue.cs(87,45): error CS1729: The type `RabbitMQ.Client.Events.EventingBasicConsumer' does not contain a constructor that takes `2' arguments
/usr/lib/mono/4.5/RabbitMQ.Client.dll (Location of the symbol related to previous error)
Compilation failed: 1 error(s), 0 warnings
```

まずは　引数の数を当てないと　関数のプロトタイプは表示されないのか。
じゃあ　自然数のように伸びていこう。

引数の数が 0 の場合

```
 mcs /r:"RabbitMQ.Client.dll" MsgQueue.cs
MsgQueue.cs(87,34): warning CS0219: The variable `consumer' is assigned but its value is never used
Compilation succeeded - 1 warning(s)
```

いけるのか。

古いドキュメントを見ると。

「public class EventingBasicConsumer」 (www.rabbitmq.com)
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

コンストラクターの引数は 0 個だが、じゃあチャンネルはどうやって渡すのか？

とりあえず先に進む。 UbuntuのRabbitMQ は v1.4 なのだろうか？

```
mcs /r:"RabbitMQ.Client.dll" MsgQueue.cs
MsgQueue.cs(97,21): error CS1502: The best overloaded method match for `RabbitMQ.Client.IModel.BasicConsume(string, System.Collections.IDictionary, RabbitMQ.Client.IBasicConsumer)' has some invalid arguments
/usr/lib/mono/4.5/RabbitMQ.Client.dll (Location of the symbol related to previous error)
MsgQueue.cs(97,46): error CS1503: Argument `#2' cannot convert `bool' expression to type `System.Collections.IDictionary'
Compilation failed: 2 error(s), 0 warnings
```

BasicConsume メソッドの引数がおかしいらしい。

v1.4では、IModelのBasicConsume はいくつか種類がある。

「BasicConsume」 (www.rabbitmq.com)
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)

RabbitMQ では

```
channel.BasicConsume(queue: "hello",
                                 noAck: true,
                                 consumer: consumer);
```

だが、v1.4では

```
string BasicConsume(ushort ticket, string queue, bool noAck, IDictionary filter, IBasicConsumer consumer)
```

この形が近いだろうか。そこで 第1引数には 0 でも、第4引数には null でも入れておく。

```
mcs /r:"RabbitMQ.Client.dll" MsgQueue.cs
MsgQueue.cs(99,21): error CS1502: The best overloaded method match for `RabbitMQ.Client.IModel.BasicConsume(string, bool, string, System.Collections.IDictionary, RabbitMQ.Client.IBasicConsumer)' has some invalid arguments
/usr/lib/mono/4.5/RabbitMQ.Client.dll (Location of the symbol related to previous error)
MsgQueue.cs(99,35): error CS1503: Argument `#1' cannot convert `int' expression to type `string'
Compilation failed: 2 error(s), 0 warnings
```

思ってたのと違うようだ。
- string
- bool
- string
- System.Collections.IDictionary
- RabbitMQ.Client.IBasicConsumer

これはなんだろうか。並びが似ているのはこれだ。

```
string BasicConsume(ushort ticket, string queue, bool noAck, string consumerTag, IDictionary filter, IBasicConsumer consumer)
```

最初の ticket が無いとすれば、consumerTag に空文字列、filter に null でも入れておけばいいだろうか？

```
mcs /r:"RabbitMQ.Client.dll" MsgQueue.cs
```

ひとまず、コンパイラは通った。

# 実行してみよう

```
./MsgQueue.exe
選べだぜ☆（＾～＾）
1   : メッセージ   送信
2   : メッセージ   受信
quit: 終了

1
メッセージを書いて[Enter]キーを押せだぜ☆（＾～＾）
AlphaBeta
 Sent(^q^) AlphaBeta
 Press [enter] to menu.

選べだぜ☆（＾～＾）
1   : メッセージ   送信
2   : メッセージ   受信
quit: 終了

2
 Please, wait receiving... Or Press [enter] to menu.
 [interrupt!] Received(^q^) AlphaBeta

選べだぜ☆（＾～＾）
1   : メッセージ   送信
2   : メッセージ   受信
quit: 終了

quit
```

動いたようだ。最後の quit でループを抜けれないのは　なんでか分からないが……。
このときバックグラウンドでは

```
jobs
[1]+  Running                 sudo rabbitmq-server &
```

sudo rabbitmq-server &
が動いていた。関係あるだろうか。

じゃあ、**Ubuntu に入っている RabbitMQ は v1.4 に似てちょっと違う何か** ということが分かった。
なぜサイトで公開されている最新版と一致しないのか？

「Verify version of rabbitmq」 (stack overflow)
http://stackoverflow.com/questions/7593269/verify-version-of-rabbitmq

RabbitMQ のバージョンを確認してみよう。

```
sudo rabbitmqctl status
```

```
Status of node 'rabbit@★～略～' ...
[{pid,28875},
 {running_applications,[{rabbit,"RabbitMQ","3.6.6"},
                        {os_mon,"CPO  CXC 138 46","2.4.1"},
                        {ranch,"Socket acceptor pool for TCP protocols.",
                               "1.2.1"},
                        {rabbit_common,[],"3.6.6"},
                        {xmerl,"XML parser","1.3.12"},
                        {mnesia,"MNESIA  CXC 138 12","4.14.1"},
                        {sasl,"SASL  CXC 138 11","3.0.1"},
                        {stdlib,"ERTS  CXC 138 10","3.1"},
                        {kernel,"ERTS  CXC 138 10","5.1"}]},
 {os,{unix,linux}},
 {erlang_version,"Erlang/OTP 19 [erts-8.1] [source-e7be63d] [64-bit] [smp:2:2] [async-threads:64] [hipe] [kernel-poll:true]\n"},
 {memory,[{total,40106344},
          {connection_readers,0},
          {connection_writers,0},
          {connection_channels,0},
          {connection_other,0},
          {queue_procs,14920},
          {queue_slave_procs,0},
          {plugins,0},
          {other_proc,13396952},
          {mnesia,62008},
          {mgmt_db,0},
          {msg_index,49040},
          {other_ets,959976},
          {binary,12296},
          {code,17800225},
          {atom,752561},
          {other_system,7058366}]},
 {alarms,[]},
 {listeners,[{clustering,25672,"::"},{amqp,5672,"::"}]},
 {vm_memory_high_watermark,0.4},
 {vm_memory_limit,416869580},
 {disk_free_limit,50000000},
 {disk_free,19432972288},
 {file_descriptors,[{total_limit,924},
                    {total_used,2},
                    {sockets_limit,829},
                    {sockets_used,0}]},
 {processes,[{limit,1048576},{used,141}]},
 {run_queue,0},
 {uptime,3036},
 {kernel,{net_ticktime,60}}]
```

3.6.6 のようだ。サイトで公開されているRabbitMQのバージョンはいくつだろうか？

「Downloading and Installing RabbitMQ」 (RabbitMQ)
https://www.rabbitmq.com/download.html

3.6.6 のようだ。**うん～～～～？？**

とりあえずソースコードを再掲しておく。

```
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 = "hello";

        static void Main(string[] args)
        {
            for (;;)
            {
                Console.WriteLine(@"選べだぜ☆（＾～＾）
1   : メッセージ   送信
2   : メッセージ   受信
quit: 終了
");

                int category = 0;
                for (;;)
                {
                    string line = Console.ReadLine();
                    switch (line)
                    {
                        case "1": category = 1; goto gt_EndLoop1;
                        case "2": category = 2; 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();
                            Send(line);
                        }
                        break;
                    case 2: Receive(); break;
                }
            }
            gt_Quit:
            ;
        }

        static void Send(string message)
        {
            ConnectionFactory factory = new ConnectionFactory() { HostName = HOST_NAME };
            IConnection connection = factory.CreateConnection();
            IModel channel = connection.CreateModel();

            channel.QueueDeclare(QUEUE_NAME, false, false, false, null);
            // Ubuntuでは何故か Spring.Messaging.Amqp.Rabbit の引数 7 つのやつになっている。
            // channel.QueueDeclare(QUEUE_NAME, false, false, false, false, false, null);

            byte[] body = Encoding.UTF8.GetBytes(message);

            channel.BasicPublish("", QUEUE_NAME, null, body);
            Console.WriteLine(" Sent(^q^) {0}", message);
            Console.WriteLine(" Press [enter] to menu.");
            Console.ReadLine();
        }

        static void Receive()
        {
            ConnectionFactory factory = new ConnectionFactory() { HostName = HOST_NAME };
            IConnection connection = factory.CreateConnection();
            IModel channel = connection.CreateModel();

            channel.QueueDeclare(QUEUE_NAME, false, false, false, null);
            // Ubuntuでは何故か Spring.Messaging.Amqp.Rabbit の引数 7 つのやつになっている。
            // channel.QueueDeclare(QUEUE_NAME, false, false, false, false, false, null);

            EventingBasicConsumer consumer = new EventingBasicConsumer(channel);
            // Ubuntuでは何故か v1.4.0 の引数が 0 個のやつになっている。
            //EventingBasicConsumer consumer = new EventingBasicConsumer();

            // 受信できたときに割り込んでくる処理
            consumer.Received += (model, ea) =>
            {
                byte[] body = ea.Body;
                string message = Encoding.UTF8.GetString(body);
                Console.WriteLine(" [interrupt!] Received(^q^) {0}", message);
            };
            channel.BasicConsume(QUEUE_NAME, true, consumer);
            // Ubuntuでは何故か引数が 5 個のやつになっている。
            // channel.BasicConsume( QUEUE_NAME, true, "", null, consumer);

            Console.WriteLine(" Please, wait receiving... Or Press [enter] to menu.");
            Console.ReadLine();
        }

    }
}
```

# 次は PHP でプロセス間通信する方法を調べよう

「【PHP】メッセージキューを使う」 (ＦＯＲ　ＳＥ)
http://forse.hatenablog.com/entry/2016/01/10/173518

じゃあ試しにページを作ってみるか。こんなんでいいんだろうか？

tamesi2.php

```
<?php
// 送信したい文字列
$msg = "hello, world";
// キューの名前は数字で 5963、パーミッションは 600 の8進数表記
$msgkey = msg_get_queue( 5963 ,0600 );
    if( !msg_send( $msgkey ,12 ,$msg ,false ) )
    {
        echo "送信失敗";
    }
    else
    {
        echo "送信 " . $msg;
    }
```

tamesi3.php

```
<?php
// キューの名前は数字で 5963
$msgkey = msg_get_queue( 5963 );
msg_receive( $msgkey ,0 ,$msgtype ,4 ,$msg,false ,null ,$err );
echo "msgtype {$msgtype} msg {$msg}\n"; 
```

# ところでメモ。あとで調べる

- foreverコマンド 常駐させる
- PHPでexpect プロセスと対話する
- 「ps aux | grep apery」で Aperyのプロセスを探せる

# PHPの続き

送信はできたのかもしれないが、受信ではメッセージを取れてないな。書き直し。

tamesi2.php

```
<?php
// 送信したい文字列
$msg = "hello, world";
// キューの名前は数字で 5963、パーミッションは 600 の8進数表記
$msgkey = msg_get_queue( 5963 ,0600 );
if( msg_send( $msgkey ,12 ,$msg ,false ) )
{
    echo "送信 " . $msg;
}
else
{
    echo "送信失敗";
}
```

tamesi3.php

```
<?php
// キューの名前は数字で 5963
$msgkey = msg_get_queue( 5963 );
if( msg_receive( $msgkey ,0 ,$msgtype ,4 ,$data ,false ,null ,$err ) )
{
    echo "msgtype {$msgtype} data {$data}"; 
}
else
{
    echo "送信失敗 " . $err;
}
```

実行結果 tamesi3.php

```
送信失敗 7
```

**へぇ。**

「posix_strerror」　(PHPマニュアル)
http://php.net/manual/ja/function.posix-strerror.php

tamesi3.php を書き直し。

```
<?php
// キューの名前は数字で 5963
$msgkey = msg_get_queue( 5963 );
if( msg_receive( $msgkey ,0 ,$msgtype ,4 ,$data ,false ,null ,$err ) )
{
    echo "msgtype {$msgtype} data {$data}"; 
}
else
{
    echo "送信失敗 " . $err . " " . posix_strerror( $err );
}
```

実行結果 tamesi3.php

```
送信失敗 7 Argument list too long
```

なんのこっちゃ。いったい何の 引数のリストか。

msg_send の第2引数の数字は　何を入れたらいいのか……？

「メッセージキューの使い方(CとPHPでプロセス間通信)」 (Linux Install Memo)
https://linux.yebisu.jp/memo/630

**おっ！ 分かった！** 

サンプル・プログラムで msg_receive 関数の第4引数が 4 なのは "test" の文字数に合わせていたのか。
4096 ぐらい大きくしておけばよかったのか。

書き直し。

tamesi2.php

```
<?php
// 送信したい文字列
$msg = "hello, world";
// キューの名前は数字
$QKey = 1111;
// パーミッションは 666 の8進数表記
$Queue = msg_get_queue( $QKey ,0666 );
echo var_dump( msg_stat_queue( $Queue ) );

if ( msg_queue_exists($QKey) )
{
    print $QKey . "はあるぜ☆（＾～＾）ｖ\n";
}
else
{
    print $QKey . "は無いぜ☆（＞＿＜）\n";
}

if( msg_send( $Queue ,12 ,$msg ,false ) )
{
    echo "送信 " . $msg . "\n";
}
else
{
    echo "送信失敗\n";
}
```

tamesi3.php

```
<?php
// キューの名前は数字
$QKey = 1111;
$Queue = msg_get_queue( $QKey );
echo var_dump( msg_stat_queue( $Queue ) );

if ( msg_queue_exists($QKey) )
{
    print $QKey . "はあるぜ☆（＾～＾）ｖ\n";
}
else
{
    print $QKey . "は無いぜ☆（＞＿＜）\n";
}

if( msg_receive( $Queue ,0 ,$msgtype ,4096 ,$msg ,false ,null ,$err ) )
{
    echo "msgtype {$msgtype} msg {$msg}\n"; 
}
else
{
    var_dump( $err );
    echo "送信失敗 " . $err . " " . posix_strerror( $err ) . "<br />";
    echo "type = " . $msgtype . " msg = " . $msg . "<br />\n";
}
```

## メッセージ・キューが空っぽのときに receive すると固まってしまうので

「[PHP]「バッチの二重処理の防ぎ方」PHP変」 (がるの健忘録)
http://d.hatena.ne.jp/gallu/20120306/p1

フラグを指定しろとのことらしい。

```
$r = msg_receive($mh, 0, $msgtype, 0xffff, $message, true, MSG_IPC_NOWAIT, $error_code);
                                                           ~~~~~~~~~~~~~~
```

でも msg_receive は「No message of desired type」というエラーを返してくる。
RabbitMQ を再起動できないものか。

# RabbitMQ を再起動

```
rabbitmqctl stop
Stopping and halting node 'rabbit@★～略～' ...
Gracefully halting Erlang VM
```

```
jobs
[1]+  Done                    sudo rabbitmq-server  (wd: /home/csg10/shogi/ukamuse_sdt4/bin)
```

で止めて、

```
rabbitmq-server
```

[Ctrl]+[Z]

```
^Z
[1]+  Stopped                 rabbitmq-server
```

```
bg 1
[1]+ rabbitmq-server &
```

で再開。

でもやっぱり 同じエラーのままだ。

キューのキー番号を変えてみたりする。今度はうまくいった。

## PHPのメッセージ・キュー・プログラムを書き直した

tamesi2.php

```
<?php
// 送信したい文字列
$msg = urldecode($_SERVER['QUERY_STRING']);
if( "" === $msg )
{
    $msg = "hello, world";
}
echo '（＾ｑ＾）' . $msg . '<br />';
echo 'これを１回クリックしろだぜ☆ｍ９（＾～＾）！<br />';
echo '<a href="http://999.999.999.999/tamesi2.php?ClickSitanDaze">http://999.999.999.999/tamesi2.php?ClickSitanDaze</a><br />';

// キューの名前は数字
$QKey = 1111;
// パーミッションは 666 の8進数表記
$Queue = msg_get_queue( $QKey ,0666 );

if ( !msg_queue_exists($QKey) )
{
    print "キュー " . $QKey . "は無いぜ☆（＞＿＜）\n";
    die("queue not found.");
}

if( !msg_send( $Queue ,12 ,$msg ,false ) )
{
    echo "エンキュー失敗☆（＞＿＜）\n";
    die("send error.");
}

echo 'そのあとこのページを見にいけだぜ☆ｍ９（＾～＾）！<br />';
echo '<a href="http://999.999.999.999/tamesi3.php">http://999.999.999.999/tamesi3.php</a><br />';
```

tamesi3.php

```
<?php
// キューの名前は数字
$QKey = 1111;
$Queue = msg_get_queue( $QKey );

if ( !msg_queue_exists($QKey) )
{
    print "キュー " . $QKey . "は無いぜ☆（＞＿＜）\n";
    die("queue not found.");
}

if( !msg_receive( $Queue ,0 ,$msgtype ,4096 ,$msg ,false ,MSG_IPC_NOWAIT ,$err ) )
{
    if( $err==42 )
    {
        echo "（＾ｑ＾）；；キューが空っぽなのかだぜ☆？<br />";
    }
    else
    {
        var_dump( $err );
        echo "デキュー失敗☆（＞＿＜） " . $err . " " . posix_strerror( $err ) . "<br />";
    }
    die("receive error.");
}

echo "プロセス間通信を通ってきたようだな☆（＾ｑ＾）「{$msg}」<br />\n"; 
echo "メッセージは溜まっているかもしれないからページを更新しろだぜ☆（＾～＾）<br />\n"; 
```

tamesi4.php （破棄に失敗するだけだったが）

```
<?php
// キューの名前は数字
$QKey = 1111;
if ( !msg_queue_exists($QKey) )
{
    print "キュー " . $QKey . "は無いぜ☆（＞＿＜）\n";
    die("queue not found.");
}

// パーミッションは 666 の8進数表記
$Queue = msg_get_queue( $QKey ,0666 );

if( !msg_remove_queue($Queue) )
{
    print "キュー " . $QKey . "の破棄に失敗☆（＞＿＜）\n";
    die("queue not removed.");
}

print "キュー " . $QKey . "を破棄したぜ☆（＾～＾）\n";
```

# PHPとC#の間で　プロセス間通信できんの？

PHPはキューの名前が数字だし、C#はキューの名前が / で始まる文字なんだっけ？
なんだろう　この違い……。

# コンパイル・オプション プリプロセッサ定義
C#の方。

「/D (プリプロセッサの定義)」 (MSDN)
https://msdn.microsoft.com/ja-jp/library/hhzbb5c8.aspx

/D を使って #define と同じような効果を出せるのか。

Ubuntu用と Windows用で分けようかな。

複数個のプリプロセッサマクロがあるとき、どう指定すればいいんだ？　そのときは適当にカンマでも打ってみるか。

# C#のプロセス間通信プログラムをさらに修正

次の点を修正した。

- レシーブに失敗すること
- quit で固まること

修正方法は、コネクションとチャンネルのクローズをちゃんとやること。

また、UbuntuとWindowsで異なる個所を UBUNTU プリプロセッサ定義で分けた。

MsgQueue.cs

```C#
// 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 = "hello";

        static Program()
        {
#if UBUNTU
            m_eventHandler_ = new BasicDeliverEventHandler((model, ea) =>
#else
            m_eventHandler_ = new EventHandler<BasicDeliverEventArgs>((model, ea) =>
#endif
            {
                byte[] body = ea.Body;
                string message = Encoding.UTF8.GetString(body);
                Console.WriteLine(" [interrupt!] Received(^q^) {0}", message);
            });
        }

        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 個のやつになっている。
                m_consumer_ = new EventingBasicConsumer();
#else
                m_consumer_ = new EventingBasicConsumer(GetChannel());
#endif

            }
            return m_consumer_;
        }
        static EventingBasicConsumer m_consumer_;

        /// <summary>
        /// 受信できたときに割り込んでくる処理
        /// </summary>
#if UBUNTU
        static BasicDeliverEventHandler m_eventHandler_;
#else
        static EventHandler<BasicDeliverEventArgs> m_eventHandler_;
#endif

        /// <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   : メッセージ   送信
2   : メッセージ   受信
quit: 終了
");

                int category = 0;
                for (;;)
                {
                    string line = Console.ReadLine();
                    switch (line)
                    {
                        case "1": category = 1; goto gt_EndLoop1;
                        case "2": category = 2; 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();
                            Send(line);
                        }
                        break;
                    case 2: Receive(); break;
                }
            }
            gt_Quit:

            // 対応するオープンは無いが、ちゃんと閉じないと、プロセスが終わってくれない。
            CloseConnection();
        }

        static void Send(string message)
        {
            IModel channel = GetChannel();

            byte[] body = Encoding.UTF8.GetBytes(message);
            channel.BasicPublish("", QUEUE_NAME, null, body);

            Console.WriteLine(" Sent(^q^) {0}", message);
            Console.WriteLine(" Press [enter] to menu.");
            Console.ReadLine();

            // 対応するオープンは無いが、ちゃんと閉じないと、レシーブしてくれない。
            CloseChannel();
        }

        static void Receive()
        {
            IModel channel = GetChannel();
            EventingBasicConsumer consumer = GetConsumer();


            // 受信できたときに割り込んでくる処理
            consumer.Received += m_eventHandler_;

#if UBUNTU
            // Ubuntuでは何故か引数が 5 個のやつになっている。
            channel.BasicConsume( QUEUE_NAME, true, "", null, consumer);
#else
            channel.BasicConsume(QUEUE_NAME, true, consumer);
#endif

            Console.WriteLine(" Please, wait receiving... Or Press [enter] to menu.");
            Console.ReadLine();

            // 割込み処理の削除
            consumer.Received -= m_eventHandler_;

            // 対応するオープンは無いが、ちゃんと閉じないと、レシーブしてくれない。
            CloseChannel();
        }

    }
}
```

(2017-03-07 修正:上のプログラム２個所修正済み)

"localhost" と埋め込んでいるところも、IPアドレスの番号に変えた方がいいんだろうか？

これを Ubuntu でコンパイルするには、

```
mcs /r:RabbitMQ.Client.dll /DUBUNTU MsgQueue.cs
```

とすればいいんだろうか？　やってみよう。

```
mcs /r:RabbitMQ.Client.dll /DUBUNTU MsgQueue.cs
error CS2007: Unrecognized command-line option: `/DUBUNTU'
```

なぜダメなのか……。

```
man mcs
～中略～
       -define:SYMLIST, -d:SYMLIST
              Defines the symbol listed by the semi-colon separated list SYMLIST  SYMBOL.   This  can  be
              tested  in  the  source code by the pre-processor, or can be used by methods that have been
              tagged with the Conditional attribute.
```

**「-define:」で始めて、セミコロンで区切ればいいのか。**

```
mcs /r:RabbitMQ.Client.dll -define:UBUNTU MsgQueue.cs
MsgQueue.cs(178,34): error CS0029: Cannot implicitly convert type `System.EventHandler<RabbitMQ.Client.Events.BasicDeliverEventArgs>' to `RabbitMQ.Client.Events.BasicDeliverEventHandler'
MsgQueue.cs(191,34): error CS0029: Cannot implicitly convert type `System.EventHandler<RabbitMQ.Client.Events.BasicDeliverEventArgs>' to `RabbitMQ.Client.Events.BasicDeliverEventHandler'
Compilation failed: 2 error(s), 0 warnings
```

プログラムにミスがあったか。
２個所修正。

```
#if UBUNTU
            m_eventHandler_ = new BasicDeliverEventHandler((model, ea) =>
#else
            m_eventHandler_ = new EventHandler<BasicDeliverEventArgs>((model, ea) =>
#endif
```

```
#if UBUNTU
        static BasicDeliverEventHandler m_eventHandler_;
#else
        static EventHandler<BasicDeliverEventArgs> m_eventHandler_;
#endif
```

# C# と PHP のプロセス間通信はどうやるのか？

"localhost" のところを IPアドレスに変えるとエラーが出てしまった。
キュー名の "hello" を "1111" に変えても　PHP では拾えなかった。

PHPマニュアルではなく、RabbitMQ の説明を読んだ方がいいのか？

「Introduction」 (RabbitMQ)
https://www.rabbitmq.com/tutorials/tutorial-one-php.html

サンプル・プログラムが全然違う。

# Ubuntu に composer のインストールが要るだろうか

「How To Install and Use Composer on Ubuntu 14.04」 (DigitalOcean)
https://www.digitalocean.com/community/tutorials/how-to-install-and-use-composer-on-ubuntu-14-04

```
sudo apt-get update
～中略～
Fetched 1,672 kB in 2s (581 kB/s)
Reading package lists... Done
```

curl も要るみたいなんだが、php5 は入れたくないぜ。

「How do I install the ext-curl extension with PHP 7?」 (stack overflow)
http://stackoverflow.com/questions/33775897/how-do-i-install-the-ext-curl-extension-with-php-7

```
sudo apt-get install php-curl
```

```
sudo service apache2 restart
```

```
curl -sS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin --filename=composer
All settings correct for using Composer
Downloading...

Composer (version 1.3.2) successfully installed to: /usr/local/bin/composer
Use it: php /usr/local/bin/composer
```

composer はダウンロードできただろうか。
起動。

```
composer
Do not run Composer as root/super user! See https://getcomposer.org/root for details
   ______
  / ____/___  ____ ___  ____  ____  ________  _____
 / /   / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/
/ /___/ /_/ / / / / / / /_/ / /_/ (__  )  __/ /
\____/\____/_/ /_/ /_/ .___/\____/____/\___/_/
                    /_/
Composer version 1.3.2 2017-01-27 18:23:41
```

何か書いてるな。

「How do I install untrusted packages safely? Is it safe to run Composer as superuser or root?」 (getcomposer.org)
https://getcomposer.org/root

root やスーパー・ユーザーじゃ composer は実行できないのだろうか？

```
cd ~
```

ルートユーザーのフォルダーに飛んだのだろうか？

```
mkdir slugify
```

フォルダを作った。

```
cd slugify
```

そのフォルダー移動した。

```
composer require cocur/slugify
Do not run Composer as root/super user! See https://getcomposer.org/root for details
```

スーパー・ユーザーから抜けるにはどうすればいいんだ？

「suコマンド（ユーザーの変更）」 (Linuxゲリラ戦記)
http://www.garunimo.com/program/linux/su.xhtml

```
su 一般ユーザー名
```

```
composer require cocur/slugify

  [ErrorException]
  file_get_contents(./composer.json): failed to open stream: Permission denied
```

なんのこっちゃ。

```
ls -an
total 20
drwxr-xr-x 3 0 0 4096 Mar  7 05:07 .
drwx------ 9 0 0 4096 Mar  7 05:05 ..
-rw-r--r-- 1 0 0   59 Mar  7 05:07 composer.json
-rw-r--r-- 1 0 0 2896 Mar  7 05:07 composer.lock
drwxr-xr-x 4 0 0 4096 Mar  7 05:07 vendor
```

ルート・ユーザーで実行するな、というから一般ユーザーになったのに……。

```
sudo su -
※パスワードを入れる
cd slugify
chmod 666 composer.json
su 一般ユーザー名
composer require cocur/slugify

  [ErrorException]
  file_get_contents(./composer.json): failed to open stream: Permission denied
```

**うーむ。**

「.composer/config file permission denied using laravel」 (stack overflow)
http://stackoverflow.com/questions/34511744/composer-config-file-permission-denied-using-laravel

```
sudo chown 一般ユーザーアカウント名 /home/一般ユーザーアカウント名/.composer/config.json
chown: cannot access '/home/★略/.composer/config.json': No such file or directory
```

**うーむ。**

```
sudo su -
cd slugify
```

スーパーユーザーでやってもだめ。

```
sudo chown 一般ユーザー名 composer.json
```

よし。カレントディレクトリのファイルをいじる権限を与えたのか。

```
su 一般ユーザー名
composer require cocur/slugify

  [ErrorException]
  file_get_contents(./composer.json): failed to open stream: Permission denied
```

だめ。

```
sudo su -
cd slugify
sudo chown 一般ユーザー名 composer.lock
```

ロックファイルを書き込む権限なんか与えたって、すぐ消えるファイルだと思うが。

一般ユーザーで。

```
sudo composer update
```

むり。

```
composer update
Composer could not find a composer.json file in /home/csg10
To initialize a project, please create a composer.json file as described in the https://getcomposer.org/ "Getting Started" section
```

「Getting Started」 (Composer)
https://getcomposer.org/doc/00-intro.md

```
php composer-setup.php --install-dir=bin --filename=composer
```

うごかない。

一般ユーザーになって、自分のホームディレクトリへ移動。

```
composer require cocur/slugify
```

と叩く。**インストールが始まった。**

```
Cannot create cache directory /home/csg10/.composer/cache/repo/https---packagist.org/, or directory is not writable. Proceeding without cache
Cannot create cache directory /home/csg10/.composer/cache/files/, or directory is not writable. Proceeding without cache
Using version ^2.4 for cocur/slugify
./composer.json has been created
Cannot create cache directory /home/csg10/.composer/cache/repo/https---packagist.org/, or directory is not writable. Proceeding without cache
Cannot create cache directory /home/csg10/.composer/cache/files/, or directory is not writable. Proceeding without cache
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
  - Installing cocur/slugify (v2.4) Downloading: 100%
Writing lock file
Generating autoload files
```

失敗したのか成功したのか分からないが、何かが起こった。

```
ls -l
total 24
-rw-rw-r-- 1 csg10 csg10   59 Mar  7 05:37 composer.json
-rw-rw-r-- 1 csg10 csg10 2896 Mar  7 05:37 composer.lock
drwxrwxr-x 2 csg10 csg10 4096 Mar  5 16:30 jikken
drwxr-xrwx 3 root  root  4096 Mar  7 00:34 shogi
-rw-r--r-- 1 root  root    14 Mar  4 03:19 Tamesi
drwxrwxr-x 4 csg10 csg10 4096 Mar  7 05:37 vendor
```

```
cat composer.json
{
    "require": {
        "cocur/slugify": "^2.4"
    }
}
```

これを、RabbitQM が言うには、

```
{ 
    "require" ： { 
        "php-amqplib / php-amqplib" ： "2.5。*" 
    } 
}
```

を、追加すればいいのか。**カンマ区切りだっけ？**

```
{
    "require": {
        "cocur/slugify": "^2.4"
    }
    ,
    "require" ： {
        "php-amqplib / php-amqplib" ： "2.5。*"
    }

}
```

このようにしてみたが。

```
composer.phar install
composer.phar: command not found
```

どうすればいいんだ。それとも、こうか？

```
{
    "require": {
        "cocur/slugify": "^2.4"
        ,
        "php-amqplib / php-amqplib" ： "2.5。*"
    }
}
```

```
composer.phar install
composer.phar: command not found
```

なんだこの読点。 **あーっ！　グーグル翻訳で　コードが変わってるじゃないか！**

```
{
    "require": {
        "cocur/slugify": "^2.4"
        ,
        "php-amqplib/php-amqplib": "2.5.*"
    }
}
```

こうだ。

```
composer.phar install
composer.phar: command not found
```

```
 composer require php-amqplib/php-amqplib
Cannot create cache directory /home/csg10/.composer/cache/repo/https---packagist.org/, or directory is not writable. Proceeding without cache
Cannot create cache directory /home/csg10/.composer/cache/files/, or directory is not writable. Proceeding without cache
Using version ^2.6 for php-amqplib/php-amqplib
./composer.json has been updated
Cannot create cache directory /home/csg10/.composer/cache/repo/https---packagist.org/, or directory is not writable. Proceeding without cache
Cannot create cache directory /home/csg10/.composer/cache/files/, or directory is not writable. Proceeding without cache
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - php-amqplib/php-amqplib v2.6.3 requires ext-bcmath * -> the requested PHP extension bcmath is missing from your system.
    - php-amqplib/php-amqplib v2.6.2 requires ext-bcmath * -> the requested PHP extension bcmath is missing from your system.
    - php-amqplib/php-amqplib v2.6.1 requires ext-bcmath * -> the requested PHP extension bcmath is missing from your system.
    - php-amqplib/php-amqplib v2.6.0 requires ext-bcmath * -> the requested PHP extension bcmath is missing from your system.
    - Installation request for php-amqplib/php-amqplib ^2.6 -> satisfiable by php-amqplib/php-amqplib[v2.6.0, v2.6.1, v2.6.2, v2.6.3].

  To enable extensions, verify that they are enabled in your .ini files:
    - /etc/php/7.0/cli/php.ini
    - /etc/php/7.0/cli/conf.d/10-opcache.ini
    - /etc/php/7.0/cli/conf.d/10-pdo.ini
    - /etc/php/7.0/cli/conf.d/15-xml.ini
    - /etc/php/7.0/cli/conf.d/20-calendar.ini
    - /etc/php/7.0/cli/conf.d/20-ctype.ini
    - /etc/php/7.0/cli/conf.d/20-curl.ini
    - /etc/php/7.0/cli/conf.d/20-dom.ini
    - /etc/php/7.0/cli/conf.d/20-exif.ini
    - /etc/php/7.0/cli/conf.d/20-fileinfo.ini
    - /etc/php/7.0/cli/conf.d/20-ftp.ini
    - /etc/php/7.0/cli/conf.d/20-gettext.ini
    - /etc/php/7.0/cli/conf.d/20-iconv.ini
    - /etc/php/7.0/cli/conf.d/20-json.ini
    - /etc/php/7.0/cli/conf.d/20-mbstring.ini
    - /etc/php/7.0/cli/conf.d/20-phar.ini
    - /etc/php/7.0/cli/conf.d/20-posix.ini
    - /etc/php/7.0/cli/conf.d/20-readline.ini
    - /etc/php/7.0/cli/conf.d/20-shmop.ini
    - /etc/php/7.0/cli/conf.d/20-simplexml.ini
    - /etc/php/7.0/cli/conf.d/20-sockets.ini
    - /etc/php/7.0/cli/conf.d/20-sysvmsg.ini
    - /etc/php/7.0/cli/conf.d/20-sysvsem.ini
    - /etc/php/7.0/cli/conf.d/20-sysvshm.ini
    - /etc/php/7.0/cli/conf.d/20-tokenizer.ini
    - /etc/php/7.0/cli/conf.d/20-wddx.ini
    - /etc/php/7.0/cli/conf.d/20-xmlreader.ini
    - /etc/php/7.0/cli/conf.d/20-xmlwriter.ini
    - /etc/php/7.0/cli/conf.d/20-xsl.ini
  You can also run `php --ini` inside terminal to see which files are used by PHP in CLI mode.

Installation failed, reverting ./composer.json to its original content.
```

あらーっ。

# php-amqplib はどうやって入手するのか？

「php-amqplib/php-amqplib」 (Git Hub)
https://github.com/php-amqplib/php-amqplib

composer.json ファイルは自分で作ってしまえばいいのか？

```
{
  "require": {
      "php-amqplib/php-amqplib": "2.6.*"
  }
}
```

```
composer.phar install
composer.phar: command not found
```

composer のインストールが終わってないのか。

# composer のインストール

「Composerをインストールしてみた」 (Qiita)
http://qiita.com/kakijin/items/02364adacf36410f449e

```
curl -sS https://getcomposer.org/installer | php
All settings correct for using Composer
Unable to write keys.dev.pub to: /home/一般ユーザー名/.composer
```

なんのこっちゃ。

```
mv composer.phar /usr/local/bin/composer
mv: cannot stat 'composer.phar': No such file or directory
```

よく見ると、

/home/一般ユーザー名/ ディレクトリに vendor というディレクトリーができていた。

```
ls
composer.json  composer.lock  jikken  shogi  Tamesi  vendor
cd vendor
ls
autoload.php  cocur  composer
cd composer
ls
autoload_classmap.php    autoload_psr4.php  autoload_static.php  installed.json
autoload_namespaces.php  autoload_real.php  ClassLoader.php      LICENSE
```

composer.phar という名前のファイルは見つからない。

「Composerで始める PHPのライブラリ管理」 (Hack Your Design!)
http://blog.toshimaru.net/how-to-use-composer-autoload/

```
curl -s https://getcomposer.org/installer | php
```

これをすると、 composer.phar は取れるらしいんだが、どこにあるんだろう？

```
curl -s https://getcomposer.org/installer | php
All settings correct for using Composer
Unable to write keys.dev.pub to: /home/★一般ユーザー名/.composer
```

うん？ .composer という隠しフォルダーができているのか？

```
ls -an
total 64
drwxr-xr-x 9 1000 1000 4096 Mar  7 06:02 .
drwxr-xr-x 3    0    0 4096 Sep 12  2015 ..
～略～
drwxr-xr-x 3    0    0 4096 Mar  7 05:30 .composer
～略～
```

あるようだ。

「Unable to write keys.dev.pub to: /home/ubuntu/.composer」 (stack overflow)
http://stackoverflow.com/questions/42413910/unable-to-write-keys-dev-pub-to-home-ubuntu-composer

```
php composer-setup.php
Could not open input file: composer-setup.php
```

```
composer
```

composer.json

```
{
    "require": {
        "php-amqplib/php-amqplib": "2.5.*"
    }
}
```

このファイルは、欲しい物を書く欄なのか。

```
composer update
```

すると、

```
Cannot create cache directory /home/★一般ユーザー名/.composer/cache/repo/https---packagist.org/, or directory is not writable. Proceeding without cache
Cannot create cache directory /home/★一般ユーザー名/.composer/cache/files/, or directory is not writable. Proceeding without cache
```

といったエラーが出てくる。

```
ls -an
total 16
drwxr-xr-x 3    0    0 4096 Mar  7 05:30 .
drwxr-xr-x 9 1000 1000 4096 Mar  7 06:29 ..
drwxr-xr-x 2    0    0 4096 Mar  7 05:30 cache
-rw-r--r-- 1    0    0   13 Mar  7 05:30 .htaccess
```

cacheディレクトリに書込みパーミッションを付けていけばいいのだろうか？

```
chmod 777 cache
chmod: changing permissions of 'cache': Operation not permitted
```

スーパーユーザーになって、一般ユーザーのフォルダーの中にある .composer ディレクトリに行く。

```
chmod 777 cache
```

一般ユーザーに戻って、自分のフォルダーの中の composer.json があるところで

```
copmoser update
```

を叩く。何かインストールが始まった。

```
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - php-amqplib/php-amqplib v2.5.2 requires ext-bcmath * -> the requested PHP extension bcmath is missing from your system.
    - php-amqplib/php-amqplib v2.5.1 requires ext-bcmath * -> the requested PHP extension bcmath is missing from your system.
    - php-amqplib/php-amqplib v2.5.0 requires ext-bcmath * -> the requested PHP extension bcmath is missing from your system.
    - Installation request for php-amqplib/php-amqplib 2.5.* -> satisfiable by php-amqplib/php-amqplib[v2.5.0, v2.5.1, v2.5.2].

  To enable extensions, verify that they are enabled in your .ini files:
    - /etc/php/7.0/cli/php.ini
    - /etc/php/7.0/cli/conf.d/10-opcache.ini
    - /etc/php/7.0/cli/conf.d/10-pdo.ini
    - /etc/php/7.0/cli/conf.d/15-xml.ini
    - /etc/php/7.0/cli/conf.d/20-calendar.ini
    - /etc/php/7.0/cli/conf.d/20-ctype.ini
    - /etc/php/7.0/cli/conf.d/20-curl.ini
    - /etc/php/7.0/cli/conf.d/20-dom.ini
    - /etc/php/7.0/cli/conf.d/20-exif.ini
    - /etc/php/7.0/cli/conf.d/20-fileinfo.ini
    - /etc/php/7.0/cli/conf.d/20-ftp.ini
    - /etc/php/7.0/cli/conf.d/20-gettext.ini
    - /etc/php/7.0/cli/conf.d/20-iconv.ini
    - /etc/php/7.0/cli/conf.d/20-json.ini
    - /etc/php/7.0/cli/conf.d/20-mbstring.ini
    - /etc/php/7.0/cli/conf.d/20-phar.ini
    - /etc/php/7.0/cli/conf.d/20-posix.ini
    - /etc/php/7.0/cli/conf.d/20-readline.ini
    - /etc/php/7.0/cli/conf.d/20-shmop.ini
    - /etc/php/7.0/cli/conf.d/20-simplexml.ini
    - /etc/php/7.0/cli/conf.d/20-sockets.ini
    - /etc/php/7.0/cli/conf.d/20-sysvmsg.ini
    - /etc/php/7.0/cli/conf.d/20-sysvsem.ini
    - /etc/php/7.0/cli/conf.d/20-sysvshm.ini
    - /etc/php/7.0/cli/conf.d/20-tokenizer.ini
    - /etc/php/7.0/cli/conf.d/20-wddx.ini
    - /etc/php/7.0/cli/conf.d/20-xmlreader.ini
    - /etc/php/7.0/cli/conf.d/20-xmlwriter.ini
    - /etc/php/7.0/cli/conf.d/20-xsl.ini
  You can also run `php --ini` inside terminal to see which files are used by PHP in CLI mode.
```

４つぐらいエラーが出ているようだ。

update じゃなくて install だったか。

```
composer install
Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Warning: The lock file is not up to date with the latest changes in composer.json. You may be getting outdated dependencies. Run update to update them.
Nothing to install or update
Generating autoload files
```

うーむ。

# bcmath

「Apparently missing bcmath dependency」 (php-amqplib/php-amqplib)
https://github.com/php-amqplib/php-amqplib/issues/312

```
composer show --platform
```

「How can I get the `bcmath` plugin in php5 in Ubuntu?」 (ask ubuntu)
http://askubuntu.com/questions/416866/how-can-i-get-the-bcmath-plugin-in-php5-in-ubuntu

```
sudo apt install php7.0-bcmath
※パスワード入力
```

なんか　インストールが始まった。 bcmath とかいう拡張子が付いたファイルを持つプロジェクトを作るんだろうか？

```
composer update
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 1 install, 0 updates, 1 removal
  - Removing cocur/slugify (v2.4)
  - Installing php-amqplib/php-amqplib (v2.5.2) Downloading: 100%
Writing lock file
Generating autoload files
```

ようやく　アップデートできたようだ。 cocur/slugify を消したのは良かったのだろうか？
もう１回やり直し。

composer.json

```
{
    "require": {
        "cocur/slugify": "^2.4"
        ,
        "php-amqplib/php-amqplib": "2.5.*"
    }
}
```

```
composer update
```

**追加で欲しいものを書くというより、欲しい現状を書くのか。**

# composer.phar

「Introduction」 (RabbitMQ)
https://www.rabbitmq.com/tutorials/tutorial-one-php.html

```
composer.phar install
composer.phar: command not found
```

依然として分からん。

```
curl -s https://getcomposer.org/installer | php
```

これをすると composer.phar が取れるんだったか？

```
All settings correct for using Composer
Unable to write keys.dev.pub to: /home/一般ユーザー名/.composer
```

.composer 隠しフォルダーがあるという話しだった。

.phar は PHPのアーカイブ（圧縮ファイル）だろうか？　解凍されてなくなってたりするんだろうか？

# var/www/html で

ユーザー・ディレクトリーではなく、var/www/html ディレクトリーで composer を使った方がいいのだろうか？

var/www/html ディレクトリーにも composer.json を置いてみる。

composer.json

```
{
    "require": {
        "php-amqplib/php-amqplib": "2.5.*"
    }
}
```

```
composer install
```

```
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
  - Installing php-amqplib/php-amqplib (v2.5.2) Loading from cache
Writing lock file
Generating autoload files
```

すんなりいった。

# __DIR__ってどこ

tamesi7.php

```
<?php
echo '__DIR__ってどこだぜ☆（＾～＾）？ = ' . __DIR__ ;
```

こういうファイルを作って、実行。

```
php tamesi7.php
__DIR__ってどこだぜ☆（＾～＾）？ = /var/www/html
```

ふむ。じゃあ、

```
require_once __DIR__ . '/vendor/autoload.php';
```

は、

```
require_once '/var/www/html/vendor/autoload.php';
```

ということになる。

```
/var/www/html/vendor$ ls -an
total 20
drwxrwxr-x 4 1000 1000 4096 Mar  7 07:01 .
drwxr-xrwx 3    0    0 4096 Mar  7 07:03 ..
-rw-rw-r-- 1 1000 1000  178 Mar  7 07:01 autoload.php
drwxrwxr-x 2 1000 1000 4096 Mar  7 07:01 composer
drwxrwxr-x 3 1000 1000 4096 Mar  7 07:01 php-amqplib
```

あるようだ。

PuTTYで実行すると。

```
php tamesi5.php
 [x] Sent 'Hello World!'
```

動いているんだが、ブラウザではアクセスできないようだ。パーミッションか？

```
 ls -an
～中略～
-rw-rw-r-- 1 1000 1000   477 Mar  7 06:00 tamesi5.php
```

PHPに実行権限なんか要るんだろうか？ PHPはデータ・ファイルだから実行ファイルではない気がする。

```
 php tamesi6.php
 [*] Waiting for messages. To exit press CTRL+C
 [x] Received bear
 [x] Received Hello World!
```

RabbitMQ は動いているんだが、ブラウザからアクセスすると動かない。

HTTP ERROR 500

# シュリンクしていくか？

数行ずつ調べていこう。

tamesi5a1.php

```
<?php
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;

echo "3行おっけ☆！（＾▽＾）<br />\n";
```

これはブラウザで見れる。

tamesi5a2.php

```
<?php
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;

$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();

$channel->close();
$connection->close();

echo "接続、チャンネル取得おっけ☆！（＾▽＾）<br />\n";
```

これもブラウザで見れる。

tamesi5a3.php

```
<?php
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;

$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();

$channel->queue_declare('hello', false, false, false, false);

$channel->close();
$connection->close();

echo "queue_declare 引数５個おっけ☆！（＾▽＾）<br />\n";
```

これもブラウザで見れる。

tamesi5a4.php

```
<?php
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;

$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();

$channel->queue_declare('hello', false, false, false, false);

$msg = new AMQPMessage('Hello World!');

$channel->close();
$connection->close();

echo "AMQPMessage おっけ☆！（＾▽＾）<br />\n";
```

これもブラウザで見れる。

tamesi5a5.php

```
<?php
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;

$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();

$channel->queue_declare('hello', false, false, false, false);

$msg = new AMQPMessage('Hello World!');
$channel->basic_publish($msg, '', 'hello');

$channel->close();
$connection->close();

echo "basic_publish おっけ☆！（＾▽＾）<br />\n";
```

これ、HTTP ERROR 500。 basic_publish がダメか？

「frame_error on basic_publish」 (pika/pika)
https://github.com/pika/pika/issues/349

localhost と書いているところが気になるが。IPアドレスに変えても変わりなし。

# PHPのエラー・ログは出てないのだろうか？

「PHPでのログ出力　まとめ」 (Qiita)
http://qiita.com/junpei_iwa/items/8dc9f62b4118186cf2df

/etc/php/7.0/apache2 ディレクトリに php.ini はあるが。
スーパーユーザーに変えて、

```
cp php.ini php.ini.original
```

でファイルをコピーしておいて、php.ini の中を見てみる。

```
display_errors = Off
```

を、

```
display_errors = On
```

に変える。外に公開していると Off にしないと内部データが見えてしまうが。

```
log_errors = On
```

これは On になっていた。
アパッチを再起動したらいいのか？

```
sudo service apache2 restart
```

**あれっ？　アパッチを再起動したら、エラーが出るどころか、PHP が動いている？**

tamesi5.php は動いたが、tamesi6.php は固まっている。これもシュリンクしてみよう。

tamesi6a1.php

```
<?php
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;

$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();

$channel->queue_declare('hello', false, false, false, false);

echo 'queue_declare までおっけ☆（＾▽＾）！', "\n";
```

これはおっけ。

tamesi6a2.php

```
<?php
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;

$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();

$channel->queue_declare('hello', false, false, false, false);

echo ' [*] Waiting for messages. To exit press CTRL+C', "\n";

$callback = function($msg) {
  echo " [x] Received ", $msg->body, "\n";
};

$channel->basic_consume('hello', '', false, true, false, false, $callback);

echo 'basic_consume までおっけ☆（＾▽＾）！', "\n";
```

これもおっけ。

ところで　ブローカーが止まっている気がする。RabbitMQ を起動させるには　どうやるんだったか。

```
rabbitmq-server
ERROR: node with name "rabbit" already running on "★略"
```

動いてるのか。

# PHPのログの出力先

/etc/php/7.0/apache2/php.ini の

```
;error_log = php_errors.log
```

の部分を

```
error_log = /var/log/php_errors.log
```

に変えた。アパッチを再起動。

```
sudo service apache2 restart
```

tamesi6a3.php

```
<?php
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;

$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();

$channel->queue_declare('hello', false, false, false, false);

echo ' [*] Waiting for messages. To exit press CTRL+C', "\n";

$callback = function($msg) {
  echo " [x] Received ", $msg->body, "\n";
};

$channel->basic_consume('hello', '', false, true, false, false, $callback);

$channel->wait();

echo 'wait() 1回ならおっけ☆（＾▽＾）！', "\n";
```

これはフリーズ。
じゃあ、ウェイトがダメなのか？

tamesi6a4.php

```
<?php
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;

$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();

$channel->queue_declare('hello', false, false, false, false);

echo ' [*] Waiting for messages. To exit press CTRL+C', "\n";

$callback = function($msg) {
  echo " [x] Received ", $msg->body, "\n";
};

$channel->basic_consume('hello', '', false, true, false, false, $callback);

sleep(3);

echo 'sleep(3)ならおっけ☆（＾▽＾）！', "\n";
```

これもおっけ☆

tamesi6a5.php

```
<?php
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;

$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();

$channel->queue_declare('hello', false, false, false, false);

echo ' [*] Waiting for messages. To exit press CTRL+C', "\n";

$callback = function($msg) {
  echo " [x] Received ", $msg->body, "\n";
};

$channel->basic_consume('hello', '', false, true, false, false, $callback);

while(count($channel->callbacks)) {
    sleep(1);
}

echo 'sleep(1)のループならおっけ☆（＾▽＾）！', "\n";
```

これはフリーズ。

# rabbitmqctl list_queues

```
rabbitmqctl list_queues
Listing queues ...
1111    0
hello   0
```

```
php tamesi5.php
 [x] Sent 'Hello World!'
rabbitmqctl list_queues
Listing queues ...
1111    0
hello   0
```

キューの中身は見れないものか。

非同期ではなく、単にデキューできないのか？

キューに入ってない気もする。

tamesi5a6.php

```
<?php
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;

$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();

$QKey = '1111';
$channel->queue_declare($QKey, false, false, false, false);

$QMsg = 'Flying Dragon!';
$msg = new AMQPMessage($QMsg);
$channel->basic_publish($msg, '', $QKey);

echo " [x] Sent '" . $QMsg . "'\n";

$channel->close();
$connection->close();
```

キーを 1111 に。

「はじめての RabbitMQ」 (CyberAgent)
http://ameblo.jp/principia-ca/entry-11233853011.html


tamesi6.php は、[Ctrl]+[C] で止める前提だから、実用できないんじゃないか？

**tamesi6.php は　受信用だから、ブラウザでアクセスするもんじゃない**んじゃないか。

$channel->wait(); が処理をブロックして、コールバック関数を呼び出しているんじゃないか。

tamesi6.php

```
<?php
// サーバーの外部からはアクセスしない。
// サーバーの内側に置いておく、受信用
//
// このプログラムは、コマンドラインで実行する
// php tamesi6.php
//
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);

echo ' [*] Waiting for messages. To exit press CTRL+C', "\n";

$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();
```

じゃあ、受信側はオッケー。

# C#とPHPは、メッセージ・キューを介して通信できんの？

C# の 1111 と、 PHPの 1111 は同じなのだろうか？見れないようだが。
フォルダー位置とか関係あるのだろうか？

関係あるのは　'localhost', 5672　ぐらいかと思うが。

# どうも C# と PHP のプロセス間通信ができてない

見ているキューが違うのか。

- 外部から tamesi2.php でエンキューした内容は、外部から tamesi3.php で見れる。（PHP）
- 外部から tamesi5.php でエンキューした内容は、内部の php tamesi6.php で見れる。（RabbitMQ）
- C# でエンキューした内容は、C# でデキューできる。(RabbitMQ)

全部　ばらばらだ。**結局、ファイルで仲介するしかないのか？**

じゃあ、tamesi6.php を常駐できないか？

# foreverコマンド

「node.js node.jsスクリプトをforeverでデーモン化する」 (でじうぃき)
http://onlineconsultant.jp/pukiwiki/?node.js%20node.js%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%82%92forever%E3%81%A7%E3%83%87%E3%83%BC%E3%83%A2%E3%83%B3%E5%8C%96%E3%81%99%E3%82%8B

これは node.js 専用だったりしないんだろうか。

「自作プログラムをデーモンとして起動させる」 (http://7ujm.net)
http://7ujm.net/linux/daemon.html

# nohup

「ログアウトしてもバックグラウンド ジョブを継続する方法」 (ソースコード探検隊)
https://www.codereading.com/nb/ignore-the-hangup-signal.html

じゃあ、こんな感じにできるのだろうか？

'''
nohup php tamesi6.php > out.log 2> err.log < /dev/null &
'''

'''
[3] 13092
jobs
[1]+  Stopped                 nano tamesi6.php
[2]   Running                 rabbitmq-server &
[3]-  Running                 nohup php tamesi6.php > out.log 2> err.log < /dev/null &
'''

試しにログアウトしてみる。

su コマンドを使い過ぎたのか、何回も exit した。

'''
jobs
'''

なんにもいなくなったが。

tamesi6.php は無限ループでなかったからか。

じゃあ、tamesi6.php を無限ループで囲って、 /var/www/html フォルダーから /home/watasi/shogi/ukamuse_sdt4/bin フォルダーへ移動しよう。

# PHPの環境を作ろう

ただ、コンピューター将棋サーバーの環境と混ざってややこしくなってしまう。

ひとまず /home/watasi/shogi/receive というディレクトリを掘ることにする。

'''
/home/csg10/shogi# mkdir receive
'''

この中に PHPプログラム用の環境を作ろう。

```
cd receive
```

次のようなファイルを作って置いておく。現状をどのような構成にしたいか書いておくファイルだ。

composer.json

```
{
    "require": {
        "php-amqplib/php-amqplib": "2.5.*"
    }
}
```

コマンドを叩く。

```
composer install
```

```
Do not run Composer as root/super user! See https://getcomposer.org/root for details
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
  - Installing php-amqplib/php-amqplib (v2.5.2) Downloading: 100%
Writing lock file
Generating autoload files
```

ルートユーザーでは走らないと書いてあるが、走っているようだが……。

```
ls
composer.json  composer.lock  vendor
```

なんか揃ってるし。PHP専用の環境にしたいんで、ディレクトリー名を php_receive にリネームするか。

```
cd ..
ls
receive  ukamuse_sdt4  ukamuse_sdt4.zip
mv receive php_receive
ls
php_receive  ukamuse_sdt4  ukamuse_sdt4.zip
```

じゃあ、ここに tamesi6.php を移動させよう。というか ここに loop6.php を書いて、tamesi6.php は削除しよう。

# loop6.php を書く

```
cd php_receive
nano loop6.php
```

でも ログアウトしたらなんで nohup でバックグラウンド起動した PHP が落ちたのだろうか。
PHP が大元から落ちたのだろうか？

「nohup: run PHP process in background」 (stack overflow)
http://stackoverflow.com/questions/5288584/nohup-run-php-process-in-background

絶対パスで指定した方がいいのか。

loop6.php

```
<?php
// 受信用
// サーバーの外部からはアクセスしない。
// サーバーの内側に置いて無限ループさせる
//
// このプログラムは、コマンドラインで実行する
//

// 操作説明を出力しておこう。ログファイルに出力されるんだろうが……
echo 'How to use'                 . "\n";
echo '=========='                 . "\n";
echo                                "\n";
echo '    Start infinity loop'    . "\n";
echo '    -------------------'    . "\n";
echo '        After ( nohup php /home/★user/shogi/php_receive/loop6.php > /home/★user/shogi/php_log/loop6.out.log 2> /home/★user/shogi/php_log/loop6.err.log < /dev/null & )' . "\n";
echo '        By absolute path.'  . "\n";
echo                                "\n";
echo '    To finish kill'         . "\n";
echo '    --------------'         . "\n";
echo '        jobs'               . "\n";
echo '        kill %(job number)' . "\n";

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();
```

ログフォルダーはここにする。
/home/★user/shogi/php_log/

```
/home/user/shogi# mkdir php_log
ls
php_log  php_receive  ukamuse_sdt4  ukamuse_sdt4.zip
```

# 動かしてみよう

http://★.★.★.★/tamesi5.php

へアクセス。

```
[x] Sent 'Flying Dragon!'
```

```
cd ..
ls
php_log  php_receive  ukamuse_sdt4  ukamuse_sdt4.zip
cd php_log
ls
loop6.err.log  loop6.out.log
nano loop6.out.log
```

```
How to use
==========

    Start infinity loop
    -------------------
        After ( nohup php /home/★user/shogi/php_receive/loop6.php > /home/★user$
        By absolute path.

    To finish kill
    --------------
        jobs
        kill %(job number)
 [x] Received Flying Dragon!
```

よし、１行書き足されている。次はログアウトする。そしてログインし直す。

```
sudo su -
※パスワード入力
jobs
```

空っぽだ。

「Run php script on background in PHP with nohup CLI」 (stack overflow)
http://stackoverflow.com/questions/9100872/run-php-script-on-background-in-php-with-nohup-cli

php コマンドも絶対パスで指定しろ、ということか。

php を /usr/bin/php に書き直す。これ、コメントか。

```
echo '        After ( nohup /usr/bin/php /home/★user/shogi/php_receive/loop6.php > /home/★user/shogi/php_log/loop6.out.log 2> /home/★user/shogi/php_log/loop6.err.log < /dev/null & )' . "\n";
```

走らせて、ログアウト、ログイン。

```
jobs
```

で空っぽ。

「ログアウトした後もプログラムの処理を続ける？（コマンド実行時にnohup）」 (kazmax)
http://kazmax.zpp.jp/linux_beginner/nohup.html

パーミッションだろうか？

```
ls -an
total 12
drwxr-xr-x 2 0 0 4096 Mar  7 19:09 .
drwxr-xrwx 5 0 0 4096 Mar  7 18:49 ..
-rw-r--r-- 1 0 0    0 Mar  7 19:06 loop6.err.log
-rw-r--r-- 1 0 0  358 Mar  7 19:06 loop6.out.log
```

ルート・ユーザーで実行しているんだから　問題ないような気もするが、
一般ユーザーのディレクトリーに置いてあることは問題か？

```
chmod 666 loop6.err.log
chmod 666 loop6.out.log
ls -an
～中略～
-rw-rw-rw- 1 0 0    0 Mar  7 19:06 loop6.err.log
-rw-rw-rw- 1 0 0  358 Mar  7 19:06 loop6.out.log
```

これでどうか？

```
logout
sudo su -
jobs
```

空っぽになっている。

「sshでログアウトしたあともコマンドを実行し続けたいときのnohupとscreen」 (don-bra.co)
http://asayamakk.hatenablog.com/entry/2016/04/09/213904

「ログアウトしてもプログラムを実行させる」 (inamuu)
http://wiki.inamuu.com/index.php?%E3%83%AD%E3%82%B0%E3%82%A2%E3%82%A6%E3%83%88%E3%81%97%E3%81%A6%E3%82%82%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%95%E3%81%9B%E3%82%8B

disown と top を調べてみるか。

「HUPシグナルとnohupとdisownとバック/フォアグラウンドジョブの理解」 (Qiita)
http://qiita.com/yushin/items/732043ee23281f19f983

「nohup コマンド &」 は　やってるんだがなぁ。

「技術/UNIX/なぜnohupをバックグランドジョブとして起動するのが定番なのか？(擬似端末, Pseudo Terminal, SIGHUP他)」 (www.glamenv-septzen.net)
https://www.glamenv-septzen.net/view/854

「nohup コマンド &」 をやって jobs が空っぽになるんだがなぁ。

「Run a nohup command over SSH, then disconnect」 (Ubuntu)
http://askubuntu.com/questions/349262/run-a-nohup-command-over-ssh-then-disconnect

# 一般ユーザーで PuTTY を使って SSHプロトコルでログインして、「nohup コマンド &」をやって exit して再度ログインすると、jobs は空っぽ。

どこから手を付けるべきか。

# ジョブとプロセスは違う

「ログアウトしてもプログラムを実行し続ける」 (Linuxコマンド逆引き大全)
http://itpro.nikkeibp.co.jp/article/COLUMN/20060228/231191/

```
ps
  PID TTY          TIME CMD
21573 pts/1    00:00:00 bash
21924 pts/1    00:00:00 ps
```

プロセスもいないが。

```
nohup /usr/bin/php /home/★user/shogi/php_receive/loop6.php > /home/★user/shogi/php_log/loop6.out.log 2> /home/★user/shogi/php_log/loop6.err.log < /dev/null &
 ps
  PID TTY          TIME CMD
21573 pts/1    00:00:00 bash
21955 pts/1    00:00:00 php
21956 pts/1    00:00:00 ps
```

ここからスーパーユーザーにログインしてみる。

```
sudo su -
ps
  PID TTY          TIME CMD
21971 pts/1    00:00:00 sudo
21972 pts/1    00:00:00 su
21973 pts/1    00:00:00 bash
21989 pts/1    00:00:00 ps
```

# シェル・スクリプトならどうか？
PHPプロセスが消えているんじゃないか。

じゃあ、シェル・スクリプトなら消えないのか？

「bash で無限ループ」 (ablog)
http://d.hatena.ne.jp/yohei-a/20090524/1243171328

loop8.sh

```
#!/bin/bash
# 無限ループの置物
while :
do
    # ここに処理を書く
    sleep 1m
done
```

「Linux / UNIX: Bash Script Sleep or Delay a Specified Amount of Time」 (nixCraft)
https://www.cyberciti.biz/faq/linux-unix-sleep-bash-scripting/

```
mkdir bash_receive
mkdir bash_log
cd bash_receive
nano loop8.sh
```

```
nohup /home/★user/shogi/bash_receive/loop8.sh > /home/★user/shogi/bash_log/loop8.out.log 2> /home/★user/shogi/bash_log/loop8.err.log < /dev/null &
[1] 22338
jobs
[1]+  Exit 126                nohup /home/★user/shogi/bash_receive/loop8.sh > /home/★user/shogi/bash_log/loop8.out.log 2> /home/★user/shogi/bash_log/loop8.err.log < /dev/null
ps
  PID TTY          TIME CMD
21971 pts/1    00:00:00 sudo
21972 pts/1    00:00:00 su
21973 pts/1    00:00:00 bash
22262 pts/1    00:00:00 ps
```

これで bash プロセスが loop8.sh を実行するジョブをやっているのか。
もう１回

```
jobs
```

空っぽだ。Exit してるんじゃないか。

# 記事が長くなったので、次の記事に移る。