前回の記事 : http://qiita.com/muzudho1/items/6fbe1681a7e14dcac3f2
バグの原因を調べよう
コンシューマの受信ループを 別スレッドにしてから おかしくなった気がする。
じゃあ、コンシューマの受信ループは 別スレッドにせず、
プロデューサーの送信を 別スレッドにしたらいいのか?
試すだけ試そう。
まず、ev_loop がエラーを出すソースコード。
// OS : Windows10 : // このプログラムは動かない
//
// OS : Ubuntu 16.04
// 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
// : Reference : Web site : 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
// : Reference : Web site : 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
// : Reference : Web site : 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)
// : Reference : Web site : C#でconstな配列を実現する (もっとクールにプログラミング) http://pgnote.net/?p=885
// : Reference : Web site : AMQP-CPP (docsforge.com) http://docsforge.com/11/AMQP-CPP/docs/latest/namespace-AMQP/class-TcpConnection/
//
// Program : this
// : Compile : Command : g++ -std=c++11 tamesi33a2_cpp.cpp -o tamesi33a2_cpp.exe -lev -lamqpcpp -pthread
// : Execute : Command : // バックグラウンドで実行
// : ./tamesi33a2_cpp.exe --msgqueue 1117 durable 1116 durable 2> ./tamesi33a2_cpp.err.log &
// : Stop : Typing : [Ctrl]+[C]
//
// メッセージの末尾に daze を付けます。
// デキューは「1112」、エンキューは「1113」キューに向けて行います。
// 標準入出力は、キーボード、画面には接続しないようにします。
#include <string> // std::string
#include <iostream> // std::cout
#include <sstream> // std::ostringstream
#include <chrono>
#include <thread> // sleep_for
#include <future> // thread
// プロセス間通信用
#include <ev.h>
#include <amqpcpp.h>
#include <amqpcpp/libev.h>
static AMQP::Address ADDRESS{ "amqp://localhost:5672" };
// 0 : enqueue用設定
// 1 : dequeue用設定
static const int ENQUEUE_INDEX = 0;
static const int DEQUEUE_INDEX = 1;
static const int NUM_INDEX = 2;
static std::string name_queues[] = { "1117", "1116" };
static std::string lifeSpan_queues[] = { "durable", "durable" };
/// <summary>
/// 回転式バッファー。
/// これはメイン・スレッドに置く。
/// デキューのスレッドでエンキューすることはできない。
/// デキュー処理は、回転式バッファーを仲介にしてエンキュー処理にメッセージを渡す。
/// </summary>
namespace rotationBuffer
{
const int bufferSize = 100;
static std::string buffer[bufferSize] = {};
static int bufferCursors[2] = { 0, 0 };
const int PUT_INDEX = 0;
const int GET_INDEX = 1;
std::mutex _mutex;
static void putMessage(std::string message)
{
std::unique_lock<std::mutex> lock(_mutex);
buffer[bufferCursors[PUT_INDEX]] = message;
bufferCursors[PUT_INDEX]++;
if (!(bufferCursors[PUT_INDEX] < bufferSize))
{
bufferCursors[PUT_INDEX] = 0;
}
}
static std::string getMessage()
{
std::unique_lock<std::mutex> lock(_mutex);
if ("" != buffer[bufferCursors[GET_INDEX]])
{
std::string message = buffer[bufferCursors[GET_INDEX]];
buffer[bufferCursors[GET_INDEX]] = "";
bufferCursors[GET_INDEX]++;
if (!(bufferCursors[GET_INDEX] < bufferSize))
{
bufferCursors[GET_INDEX] = 0;
}
return message;
}
return "";
}
}
// メッセージキューにエンキュー
static void enqueue(struct ev_loop* loop, AMQP::TcpConnection& connection, AMQP::TcpChannel& channel, std::string message)
{
std::string exchange_name = "myexchange";
std::string routing_key = "";
int lifeSpan = 0;
std::string a = lifeSpan_queues[ENQUEUE_INDEX];
if ("durable" == a) { lifeSpan = AMQP::durable; }
else if ("autodelete" == a) { lifeSpan = AMQP::autodelete; }
else if ("passive" == a) { lifeSpan = AMQP::passive; }
else if ("exclusive" == a) { lifeSpan = AMQP::exclusive; }
else
{
std::cerr << "未対応のキュー寿命が指定されました。["+ a +"]" << std::endl;
exit(1);
}
channel.declareQueue(name_queues[ENQUEUE_INDEX], lifeSpan)
.onError([&a](const char* errMsg) {
std::cerr << "error declaring queue: " << errMsg << " lifeSpan=[" << a << "]" << "\n";
});
channel.bindQueue(exchange_name, name_queues[ENQUEUE_INDEX], routing_key)
.onSuccess([&connection, &channel, &exchange_name, &routing_key, &message]() {
if (!channel.publish(exchange_name, routing_key, message.c_str(), message.size())) {
std::cerr << "failed to publish?\n";
}
// break in ev loop.
connection.close();
});
// このループは、パブリッシュ後に抜ける
ev_run(loop);
}
// 受信できたときに割り込んでくる処理
// startConsume() しておくこと。
static std::string dequeue() {
std::string message;
while ("" == message)
{
message = rotationBuffer::getMessage();
}
return message;
}
// メッセージ・キューの監視を開始
static void workConsume()
{
// Connect to the AMQP service.
auto *loop = EV_DEFAULT;
AMQP::LibEvHandler handler(loop);
AMQP::TcpConnection connection(&handler, ADDRESS);
AMQP::TcpChannel channel(&connection);
// I will go to the front of the box named "1111".
int lifeSpan = 0;
std::string a = lifeSpan_queues[DEQUEUE_INDEX];
if ("durable" == a) { lifeSpan = AMQP::durable; }
else if ("autodelete" == a) { lifeSpan = AMQP::autodelete; }
else if ("passive" == a) { lifeSpan = AMQP::passive; }
else if ("exclusive" == a) { lifeSpan = AMQP::exclusive; }
else {
std::cerr << "未対応のキュー寿命が指定されました。[" + a + "]" << std::endl;
exit(1);
}
channel.declareQueue(name_queues[DEQUEUE_INDEX], lifeSpan);
// I look inside the box.
auto errorCb = [&a](const char *errMsg) {
std::cerr << "My ID watching failed [" << errMsg << "] lifeSpan=[" << a << "]" << std::endl;
};
auto messageCb = [&channel](const AMQP::Message &message, uint64_t deliveryTag, bool redelivered) {
std::string myString(message.body(), message.bodySize());
rotationBuffer::putMessage(myString);
channel.ack(deliveryTag);
};
channel.consume(name_queues[DEQUEUE_INDEX])
.onReceived(messageCb)
.onError(errorCb);
// I will keep on forever.
ev_run(loop, 0);
// I will not come here.
return;
}
int main(int argc, char* argv[])
{
std::string cmdArg;
// プログラム名を省き、コマンドライン引数だけをつなげる。
for (int i = 1; i < argc; ++i)
{
cmdArg += std::string(argv[i]) + " ";
}
std::istringstream ssCmd(cmdArg);
// 半角スペース区切りの最初の1トークンを拾う
std::string token;
ssCmd >> token;
if (token == "--msgqueue") {
// ex.) --msgqueue 1115 durable 1114 durable
ssCmd >> name_queues[ENQUEUE_INDEX];
ssCmd >> lifeSpan_queues[ENQUEUE_INDEX];
ssCmd >> name_queues[DEQUEUE_INDEX];
ssCmd >> lifeSpan_queues[DEQUEUE_INDEX];
}
// デキューの常時監視をスタート
auto th1 = std::thread([] { workConsume(); });
// エンキュー用の接続
//auto* loop = EV_DEFAULT;
struct ev_loop* loop = EV_DEFAULT;
AMQP::LibEvHandler handler{ loop };
AMQP::TcpConnection connection{ &handler, ADDRESS };
AMQP::TcpChannel channel{ &connection };
// 無限ループ
for (;;)
{
std::string message = rotationBuffer::getMessage();
if ("" != message)
{
// 末尾に daze を付ける。
message += "daze";
// エンキューする
enqueue(loop, connection, channel, message);
}
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
// このプログラムは、自分では接続を切らない。
// th1 スレッドの終了を待つ
th1.join();
return 0;
}
これを改造することにする。
現状
- デキューを別スレッドにする
- エンキューの無限ループを回す
にしているが、次のように変える。
- エンキューを別スレッドにする
- デキューの ev_loop を置いておくに任せる
何が違うのか、という気はする。
名前は tamesi35a2_cpp.cpp にする
ちょっと待て。
無限ループの外で接続して、無限ループの中で切断してないか?
これでは 接続と切断の1対1対応が 崩れている。
いったん、tamesi33a2_cpp.cpp のこの部分を直そう。
tamesi35a2_cpp.cpp
// OS : Windows10 : // このプログラムは動かない
//
// OS : Ubuntu 16.04
// 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
// : Reference : Web site : 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
// : Reference : Web site : 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
// : Reference : Web site : 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)
// : Reference : Web site : C#でconstな配列を実現する (もっとクールにプログラミング) http://pgnote.net/?p=885
// : Reference : Web site : AMQP-CPP (docsforge.com) http://docsforge.com/11/AMQP-CPP/docs/latest/namespace-AMQP/class-TcpConnection/
//
// Program : this
// : Compile : Command : g++ -std=c++11 tamesi35a2_cpp.cpp -o tamesi35a2_cpp.exe -lev -lamqpcpp -pthread
// : Execute : Command : // バックグラウンドで実行
// : ./tamesi35a2_cpp.exe --msgqueue 1117 durable 1116 durable 2> ./tamesi35a2_cpp.err.log &
// : Stop : Typing : [Ctrl]+[C]
//
// メッセージの末尾に daze を付けます。
// デキューは「1112」、エンキューは「1113」キューに向けて行います。
// 標準入出力は、キーボード、画面には接続しないようにします。
#include <string> // std::string
#include <iostream> // std::cout
#include <sstream> // std::ostringstream
#include <chrono>
#include <thread> // sleep_for
#include <future> // thread
// プロセス間通信用
#include <ev.h>
#include <amqpcpp.h>
#include <amqpcpp/libev.h>
static AMQP::Address ADDRESS{ "amqp://localhost:5672" };
// 0 : enqueue用設定
// 1 : dequeue用設定
static const int ENQUEUE_INDEX = 0;
static const int DEQUEUE_INDEX = 1;
static const int NUM_INDEX = 2;
static std::string name_queues[] = { "1117", "1116" };
static std::string lifeSpan_queues[] = { "durable", "durable" };
/// <summary>
/// 回転式バッファー。
/// これはメイン・スレッドに置く。
/// デキューのスレッドでエンキューすることはできない。
/// デキュー処理は、回転式バッファーを仲介にしてエンキュー処理にメッセージを渡す。
/// </summary>
namespace rotationBuffer
{
const int bufferSize = 100;
static std::string buffer[bufferSize] = {};
static int bufferCursors[2] = { 0, 0 };
const int PUT_INDEX = 0;
const int GET_INDEX = 1;
std::mutex _mutex;
static void putMessage(std::string message)
{
std::unique_lock<std::mutex> lock(_mutex);
buffer[bufferCursors[PUT_INDEX]] = message;
bufferCursors[PUT_INDEX]++;
if (!(bufferCursors[PUT_INDEX] < bufferSize))
{
bufferCursors[PUT_INDEX] = 0;
}
}
static std::string getMessage()
{
std::unique_lock<std::mutex> lock(_mutex);
if ("" != buffer[bufferCursors[GET_INDEX]])
{
std::string message = buffer[bufferCursors[GET_INDEX]];
buffer[bufferCursors[GET_INDEX]] = "";
bufferCursors[GET_INDEX]++;
if (!(bufferCursors[GET_INDEX] < bufferSize))
{
bufferCursors[GET_INDEX] = 0;
}
return message;
}
return "";
}
}
// メッセージキューにエンキュー
static void enqueue(std::string message)
{
// エンキュー用の接続
//auto* loop = EV_DEFAULT;
struct ev_loop* loop = EV_DEFAULT;
AMQP::LibEvHandler handler{ loop };
AMQP::TcpConnection connection{ &handler, ADDRESS };
AMQP::TcpChannel channel{ &connection };
std::string exchange_name = "myexchange";
std::string routing_key = "";
int lifeSpan = 0;
std::string a = lifeSpan_queues[ENQUEUE_INDEX];
if ("durable" == a) { lifeSpan = AMQP::durable; }
else if ("autodelete" == a) { lifeSpan = AMQP::autodelete; }
else if ("passive" == a) { lifeSpan = AMQP::passive; }
else if ("exclusive" == a) { lifeSpan = AMQP::exclusive; }
else
{
std::cerr << "未対応のキュー寿命が指定されました。[" + a + "]" << std::endl;
exit(1);
}
channel.declareQueue(name_queues[ENQUEUE_INDEX], lifeSpan)
.onError([&a](const char* errMsg) {
std::cerr << "error declaring queue: " << errMsg << " lifeSpan=[" << a << "]" << "\n";
});
channel.bindQueue(exchange_name, name_queues[ENQUEUE_INDEX], routing_key)
.onSuccess([&connection, &channel, &exchange_name, &routing_key, &message]() {
if (!channel.publish(exchange_name, routing_key, message.c_str(), message.size())) {
std::cerr << "failed to publish?\n";
}
// break in ev loop.
connection.close();
});
// このループは、パブリッシュ後に抜ける
ev_run(loop);
}
// 受信できたときに割り込んでくる処理
// startConsume() しておくこと。
static std::string dequeue() {
std::string message;
while ("" == message)
{
message = rotationBuffer::getMessage();
}
return message;
}
//// メッセージ・キューの送信を担当
//static void workProduce()
//{
//
//}
// メッセージ・キューの監視を開始
static void workConsume()
{
// Connect to the AMQP service.
auto *loop = EV_DEFAULT;
AMQP::LibEvHandler handler(loop);
AMQP::TcpConnection connection(&handler, ADDRESS);
AMQP::TcpChannel channel(&connection);
// I will go to the front of the box named "1111".
int lifeSpan = 0;
std::string a = lifeSpan_queues[DEQUEUE_INDEX];
if ("durable" == a) { lifeSpan = AMQP::durable; }
else if ("autodelete" == a) { lifeSpan = AMQP::autodelete; }
else if ("passive" == a) { lifeSpan = AMQP::passive; }
else if ("exclusive" == a) { lifeSpan = AMQP::exclusive; }
else {
std::cerr << "未対応のキュー寿命が指定されました。[" + a + "]" << std::endl;
exit(1);
}
channel.declareQueue(name_queues[DEQUEUE_INDEX], lifeSpan);
// I look inside the box.
auto errorCb = [&a](const char *errMsg) {
std::cerr << "My ID watching failed [" << errMsg << "] lifeSpan=[" << a << "]" << std::endl;
};
auto messageCb = [&channel](const AMQP::Message &message, uint64_t deliveryTag, bool redelivered) {
std::string myString(message.body(), message.bodySize());
rotationBuffer::putMessage(myString);
channel.ack(deliveryTag);
};
channel.consume(name_queues[DEQUEUE_INDEX])
.onReceived(messageCb)
.onError(errorCb);
// I will keep on forever.
ev_run(loop, 0);
// I will not come here.
return;
}
int main(int argc, char* argv[])
{
std::string cmdArg;
// プログラム名を省き、コマンドライン引数だけをつなげる。
for (int i = 1; i < argc; ++i)
{
cmdArg += std::string(argv[i]) + " ";
}
std::istringstream ssCmd(cmdArg);
// 半角スペース区切りの最初の1トークンを拾う
std::string token;
ssCmd >> token;
if (token == "--msgqueue") {
// ex.) --msgqueue 1115 durable 1114 durable
ssCmd >> name_queues[ENQUEUE_INDEX];
ssCmd >> lifeSpan_queues[ENQUEUE_INDEX];
ssCmd >> name_queues[DEQUEUE_INDEX];
ssCmd >> lifeSpan_queues[DEQUEUE_INDEX];
}
// デキューの常時監視をスタート
auto th1 = std::thread([] { workConsume(); });
// 無限ループ
for (;;)
{
std::string message = rotationBuffer::getMessage();
if ("" != message)
{
// 末尾に daze を付ける。
message += "daze";
// エンキューする
enqueue( message);
}
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
// このプログラムは、自分では接続を切らない。
// th1 スレッドの終了を待つ
th1.join();
return 0;
}
# g++ -std=c++11 tamesi35a2_cpp.cpp -o tamesi35a2_cpp.exe -lev -lamqpcpp -pthread
# ./tamesi35a2_cpp.exe --msgqueue 1117 durable 1116 durable 2> ./tamesi35a2_cpp.err.log &
[1] 20175
# ./tamesi33a2_cpp.exe --msgqueue 1117 durable 1116 durable &
[2] 20225
My ID watching failed [Channel is in error state] lifeSpan=[durable]
うーむ。
# ps aux | grep .exe
root 1743 3.5 0.0 126580 52 ? Sl Mar11 153:59 /usr/bin/cli ./loop28_cs.exe
root 1820 0.0 0.0 4216 12 ? S Mar11 0:24 ./loop28_cpp.exe
root 3554 0.2 0.4 179196 4916 ? Sl Mar13 2:11 ./tamesi33a2_cpp.exe
root 7457 0.2 0.2 244736 2904 ? Sl Mar13 1:49 ./tamesi33a2_cpp.exe --msgqueue 1117 durable 1116 durable
root 11288 0.2 0.4 341724 4428 ? Sl Mar11 9:53 /usr/bin/cli ./tamesi33a2_cs.exe
root 20175 0.2 0.3 170872 3156 pts/6 Sl 07:28 0:00 ./tamesi35a2_cpp.exe --msgqueue 1117 durable 1116 durable
root 20225 0.2 0.2 244736 2876 pts/6 Sl 07:31 0:00 ./tamesi33a2_cpp.exe --msgqueue 1117 durable 1116 durable
root 20240 0.2 0.2 179200 2984 pts/6 Sl 07:32 0:00 ./tamesi33a2_cpp.exe --msgqueue 1117 durable 1116 durable
root 20259 0.0 0.0 12936 988 pts/6 S+ 07:33 0:00 grep --color=auto .exe
なんか いっぱい動いてるな。止めるか。
# kill 1743
# kill 1820
# kill 3554
# kill 7457
# kill 11288
# kill 20175
# kill 20225
[1] Terminated ./tamesi35a2_cpp.exe --msgqueue 1117 durable 1116 durable 2> ./tamesi35a2_cpp.err.log
# kill 20240
[2]- Terminated ./tamesi33a2_cpp.exe --msgqueue 1117 durable 1116 durable
# ps aux | grep .exe
root 20296 0.0 0.0 12936 984 pts/6 S+ 07:35 0:00 grep --color=auto .exe
[3]+ Terminated ./tamesi33a2_cpp.exe --msgqueue 1117 durable 1116 durable
起動するプログラム番号も間違えてるし。
# ./tamesi35a2_cpp.exe --msgqueue 1117 durable 1116 durable &
[1] 20308
My ID watching failed [Channel is in error state] lifeSpan=[durable]
# ./tamesi35a2_cpp.exe --msgqueue 1117 durable 1116 durable &
[2] 20324
My ID watching failed [Channel is in error state] lifeSpan=[durable]
うーむ。
# ./tamesi35a2_cpp.exe --msgqueue 1117 durable 1116 durable 2> ./tamesi35a2_cpp.err.log &
[3] 20489
Welcome! AMQP::durable=[1] AMQP::autodelete=[2] AMQP::passive=[8] AMQP::exclusive=[512]
ためしに値を出力したら うまくいったぞ?
# ./tamesi34_cs.exe
削除したいキューがあれば名前を、無ければ空文字列を入れろだぜ☆(^~^)
キュー名を入力 : キューを削除します
空文字列で[Enter] : 次のステップへ進む
Name or empty ? >
エンキュー先のメッセージ・キューの名前を入れろだぜ☆(^~^)
Queue name? > 1116
エンキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(1) durable : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが1人も接続していなかったら消す
(4) passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > 1
デキュー先のメッセージ・キューの名前を入れろだぜ☆(^~^)
Queue name? > 1117
デキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(1) durable : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが1人も接続していなかったら消す
(4) passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > 1
GetChannel index = [1]
QUEUE_NAMES[index] = [1117]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [False]
nowait は仮に false 固定
arguments は仮に null 固定
終了するときは[Ctrl]+[C]キーを押せだぜ☆(^~^)
エンキューするときはメッセージを打ち込んで[Enter]キーを押せだぜ☆(^◇^)
Enqueue? > usi
GetChannel index = [0]
QUEUE_NAMES[index] = [1116]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [False]
nowait は仮に false 固定
arguments は仮に null 固定
Unhandled Exception:
RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=406, text="PRECONDITION_FAILED - inequivalent arg 'durable' for queue '1116' in vhost '/': received 'true' but current is 'false'", classId=50, methodId=10, cause=
at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply () <0x41a50410 + 0x00107> in <filename unknown>:0
at RabbitMQ.Client.Impl.ModelBase.ModelRpc (RabbitMQ.Client.Impl.MethodBase method, RabbitMQ.Client.Impl.ContentHeaderBase header, System.Byte[] body) <0x41a4e290 + 0x000fd> in <filename unknown>:0
at RabbitMQ.Client.Framing.Impl.v0_8.Model.QueueDeclare (System.String queue, Boolean passive, Boolean durable, Boolean exclusive, Boolean autoDelete, Boolean nowait, IDictionary arguments) <0x41a526b0 + 0x00113> in <filename unknown>:0
at UsagiMQ.Program.GetChannel (Int32 index) <0x41a13d20 + 0x00436> in <filename unknown>:0
at UsagiMQ.Program.Enqueue (System.String message) <0x41a537c0 + 0x00013> in <filename unknown>:0
at UsagiMQ.Program.Main (System.String[] args) <0x41a0ed50 + 0x0099f> in <filename unknown>:0
[ERROR] FATAL UNHANDLED EXCEPTION: RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=406, text="PRECONDITION_FAILED - inequivalent arg 'durable' for queue '1116' in vhost '/': received 'true' but current is 'false'", classId=50, methodId=10, cause=
at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply () <0x41a50410 + 0x00107> in <filename unknown>:0
at RabbitMQ.Client.Impl.ModelBase.ModelRpc (RabbitMQ.Client.Impl.MethodBase method, RabbitMQ.Client.Impl.ContentHeaderBase header, System.Byte[] body) <0x41a4e290 + 0x000fd> in <filename unknown>:0
at RabbitMQ.Client.Framing.Impl.v0_8.Model.QueueDeclare (System.String queue, Boolean passive, Boolean durable, Boolean exclusive, Boolean autoDelete, Boolean nowait, IDictionary arguments) <0x41a526b0 + 0x00113> in <filename unknown>:0
at UsagiMQ.Program.GetChannel (Int32 index) <0x41a13d20 + 0x00436> in <filename unknown>:0
at UsagiMQ.Program.Enqueue (System.String message) <0x41a537c0 + 0x00013> in <filename unknown>:0
at UsagiMQ.Program.Main (System.String[] args) <0x41a0ed50 + 0x0099f> in <filename unknown>:0
このエラーも分からずじまい。
接続部分を直そう。
あれっ、直してこれか。
じゃあ、C++ と C# で送受信テストしてみよう。
# ps aux | grep exe
root 20308 0.2 0.3 170872 3156 pts/6 Sl 07:35 0:02 ./tamesi35a2_cpp.exe --msgqueue 1117 durable 1116 durable
root 20324 0.2 0.5 170872 5188 pts/6 Sl 07:36 0:01 ./tamesi35a2_cpp.exe --msgqueue 1117 durable 1116 durable
root 20489 0.2 0.3 170872 3136 pts/6 Sl 07:42 0:00 ./tamesi35a2_cpp.exe --msgqueue 1117 durable 1116 durable
root 20587 0.0 0.0 12936 988 pts/6 S+ 07:48 0:00 grep --color=auto exe
なんで こんなにプロセス立ってるんだろな。
C# ではシングルトンでやってた
tamesi33a2_cs.cs
// OS : Windows 10
// IDE : Visual Studio 2015
// Install : NuGet : Install-Package RabbitMQ.Client -Version 4.1.1
//
// OS : Ubuntu 16.04
// Compile : Command : mcs /r:RabbitMQ.Client.dll -define:UBUNTU tamesi33a2_cs.cs
// : Command : chmod 755 tamesi33a2_cs.cs
// Execute : Command : // バックグラウンドで実行する
// : nohup ./tamesi33a2_cs.exe > ./tamesi33a2_cs.out.log 2> ./tamesi33a2_cs.err.log < /dev/null &
// Check : : // tamesi33a1_cs.exe を使う
//--------------------------------------------------------------------------------
// tamesi33a2_cs.cs
// Ubuntu の RabbitMQ はソースのバージョンが古いのか、API が異なった。
// #define UBUNTU
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Collections.ObjectModel;
using System.Text;
using System.Threading;
namespace UsagiMQ
{
/// <summary>
/// メッセージの末尾に daze を付けます。
/// デキューは「1112」、エンキューは「1113」キューに向けて行います。
/// 標準入出力は、キーボード、画面には接続しないようにします。
///
/// 参照 : 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)
/// 参照 : C#でconstな配列を実現する (もっとクールにプログラミング) http://pgnote.net/?p=885
/// </summary>
class Program
{
public const string HOST_NAME = "localhost";
public static readonly ReadOnlyCollection<string> QUEUE_NAMES =
Array.AsReadOnly(new string[] { "1113", "1112" });
public const int ENQUEUE_INDEX = 0;
public const int DEQUEUE_INDEX = 1;
// 回転式バッファー
public static RotationBuffer rollingBuffer = new RotationBuffer();
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 bool IsConnected()
{
if (null != m_connection_)
{
return m_connection_.IsOpen;
}
return false;
}
public static IModel GetChannel(int index)
{
if (null == m_channels_[index])
{
m_channels_[index] = GetConnection().CreateModel();
#if UBUNTU
// Ubuntuでは何故か Spring.Messaging.Amqp.Rabbit の引数 7 つのやつになっている。
m_channels_[index].QueueDeclare(QUEUE_NAMES[index], false, false, false, false, false, null);
#else
m_channels_[index].QueueDeclare(QUEUE_NAMES[index], false, false, false, null);
#endif
}
return m_channels_[index];
}
static IModel[] m_channels_ = new IModel[2];
public static EventingBasicConsumer GetConsumer(int index)
{
if (null == m_consumers_[index])
{
#if UBUNTU
// Ubuntuでは何故か v1.4.0 の引数が 0 個のやつになっている。調べたが引数が1個~6個のものは無かった。
m_consumers_[index] = new EventingBasicConsumer();
#else
m_consumers_[index] = new EventingBasicConsumer(GetChannel(index));
#endif
}
return m_consumers_[index];
}
static EventingBasicConsumer[] m_consumers_ = new EventingBasicConsumer[2];
/// <summary>
/// 受信できたときに割り込んでくる処理
/// </summary>
#if UBUNTU
public static BasicDeliverEventHandler GetReceiveHandler()
#else
public static EventHandler<BasicDeliverEventArgs> GetReceiveHandler()
#endif
{
if (null == m_eventHandler_)
{
#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);
// 末尾に daze を付ける。
message += "daze";
// 回転式バッファーに入れる
rollingBuffer.PutMessage(message);
});
}
return m_eventHandler_;
}
#if UBUNTU
static BasicDeliverEventHandler m_eventHandler_;
#else
static EventHandler<BasicDeliverEventArgs> m_eventHandler_;
#endif
/// <summary>
/// 対応するオープンは無いけれど、開けたら閉める、を完璧に対応する必要がある。
/// </summary>
static void CloseChannel(int index)
{
if (null != m_channels_[index])
{
m_channels_[index].Close();
m_channels_[index] = null;
}
}
static void Main(string[] args)
{
// 常時監視をスタート
StartDequeue();
// 無限ループ
while (IsConnected())
{
string message = rollingBuffer.GetMessage();
if (null != message)
{
// エンキューする
Enqueue(message);
}
Thread.Sleep(20);
}
// このプログラムは、自分では接続を切らない。
}
static void Enqueue(string message)
{
IModel channel = GetChannel(ENQUEUE_INDEX);
byte[] body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish("", QUEUE_NAMES[ENQUEUE_INDEX], null, body);
// 対応するオープンは無いが、ちゃんと閉じないと、レシーブしてくれない。
CloseChannel(ENQUEUE_INDEX);
}
static void StartDequeue()
{
IModel channel = GetChannel(DEQUEUE_INDEX);
EventingBasicConsumer consumer = GetConsumer(DEQUEUE_INDEX);
// 受信できたときに割り込んでくる処理
consumer.Received += GetReceiveHandler();
#if UBUNTU
// Ubuntuでは何故か引数が 5 個のやつになっている。
channel.BasicConsume( QUEUE_NAMES[DEQUEUE_INDEX], true, "", null, consumer);
#else
channel.BasicConsume( QUEUE_NAMES[DEQUEUE_INDEX], true, consumer);
#endif
// 割込み処理の削除
// consumer.Received -= GetReceiveHandler();
// 対応するオープンは無いが、ちゃんと閉じないと、レシーブしてくれない。
// CloseChannel(DEQUEUE_INDEX);
}
}
/// <summary>
/// 回転式バッファー。
/// これはメイン・スレッドに置く。
/// デキューのスレッドでエンキューすることはできない。
/// デキュー処理は、回転式バッファーを仲介にしてエンキュー処理にメッセージを渡す。
/// </summary>
public class RotationBuffer
{
public const int bufferSize = 100;
public string[] buffer = new string[bufferSize];
public int[] bufferCursors = new int[] { 0, 0 };
public const int PUT_INDEX = 0;
public const int GET_INDEX = 1;
public void PutMessage(string message)
{
buffer[bufferCursors[PUT_INDEX]] = message;
bufferCursors[PUT_INDEX]++;
if (!(bufferCursors[PUT_INDEX] < bufferSize))
{
bufferCursors[PUT_INDEX] = 0;
}
}
public string GetMessage()
{
if (null != buffer[bufferCursors[GET_INDEX]])
{
string message = buffer[bufferCursors[GET_INDEX]];
buffer[bufferCursors[GET_INDEX]] = null;
bufferCursors[GET_INDEX]++;
if (!(bufferCursors[GET_INDEX] < bufferSize))
{
bufferCursors[GET_INDEX] = 0;
}
return message;
}
return null;
}
}
}
番号を合わせて tamesi35a2_cs.cs に変えてみる
キュー名も選べるように改造しよう。 tamesi34_cs.cs ではそういう機能を入れていた。
tamesi34_cs.cs
// OS : Windows 10
// IDE : Visual Studio 2015
// Install : NuGet : Install-Package RabbitMQ.Client -Version 4.1.1
//
// OS : Ubuntu 16.04
// Compile : Command : mcs /r:RabbitMQ.Client.dll -define:UBUNTU tamesi34_cs.cs
// : Command : // chmod 755 tamesi34_cs.cs
// Execute : Command : // フォアグラウンドで実行する
// : ./tamesi34_cs.exe 2> ./tamesi34_cs.err.log
// Check : Command : // キューの中身の数を調べる
// : rabbitmqctl list_queues
//
// Library : RabbitMQ
// Refference : Website : RabbitMQ http://www.rabbitmq.com/
// : Website : RabbitMQ管理コマンド(rabbitmqctl)使い方 (Qiita) http://qiita.com/tamikura@github/items/5293cda4c0026b2d7022
// : Website : amqpを使ってRabbitMQのキューを操作する (Qiita) http://qiita.com/tamikura@github/items/a268afa51c5537ca4fe6
//--------------------------------------------------------------------------------
// tamesi34_cs.cs
// Ubuntu の RabbitMQ はソースのバージョンが古いのか、API が異なった。
// #define UBUNTU
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Text;
namespace UsagiMQ
{
[Flags]
enum LifeSpanType
{
/// <summary>
/// RabbitMQが止まってもキューを残す
/// </summary>
Durable = 1,
/// <summary>
/// コンシューマーが1人も接続していなかったら消す
/// </summary>
Autodelete = 0x1<<1,
/// <summary>
/// キューが存在するかどうかチェックするだけ。中身見ない時これ
/// </summary>
Passive = 0x1 << 2,
/// <summary>
/// この接続でだけ使える。この接続が切れたら消す
/// </summary>
Exclusive = 0x1 << 3
}
/// <summary>
/// メッセージを エンキューします。
/// キューの名前は指定してください。
/// デキューは割込みを受け付けます。
///
/// 参照 : QueueDeclare (v1.0) 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
/// 参照 : QueueDelete (v1.4) 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.QueueDelete(System.UInt16,System.String,System.Boolean,System.Boolean,System.Boolean)
/// 参照 : 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)
/// 参照 : C#でconstな配列を実現する (もっとクールにプログラミング) http://pgnote.net/?p=885
/// </summary>
class Program
{
const int ENQUEUE_INDEX = 0;
const int DEQUEUE_INDEX = 1;
const int DELETEQUEUE_INDEX = 2;
const int NUM_INDEX = 3;
const string HOST_NAME = "localhost";
static string[] QUEUE_NAMES = new string[NUM_INDEX];
/// <summary>
/// キューの寿命(複合可能)
/// durable : RabbitMQが止まってもキューを残す
/// autodelete : コンシューマーが1人も接続していなかったら消す
/// passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
/// exclusive : この接続でだけ使える。この接続が切れたら消す
/// </summary>
static LifeSpanType[] lifeSpans_queue = new LifeSpanType[NUM_INDEX];
static bool[]
durable_lifeSpans = new bool[NUM_INDEX],
autodelete_lifeSpans = new bool[NUM_INDEX],
passive_lifeSpans = new bool[NUM_INDEX],
exclusive_lifeSpans = new bool[NUM_INDEX];
/// <summary>
///
/// </summary>
/// <param name="index_queue"></param>
/// <param name="name_queue"></param>
/// <param name="lifeSpan">
/// (0) durable
/// (1) autodelete
/// (2) passive
/// (3) exclusive
/// </param>
static void SetLifeSpan(int index_queue, string name_queue, LifeSpanType lifeSpan)
{
QUEUE_NAMES[index_queue] = name_queue;
lifeSpans_queue[index_queue] = lifeSpan;
// 一旦クリアー
durable_lifeSpans[index_queue] = false;
autodelete_lifeSpans[index_queue] = false;
passive_lifeSpans[index_queue] = false;
exclusive_lifeSpans[index_queue] = false;
// durable
if (((int)lifeSpan & (int)LifeSpanType.Durable) == (int)LifeSpanType.Durable) { durable_lifeSpans[index_queue] = true; }
// autodelete
if (((int)lifeSpan & (int)LifeSpanType.Autodelete) == (int)LifeSpanType.Autodelete) { autodelete_lifeSpans[index_queue] = true; }
// passive
if (((int)lifeSpan & (int)LifeSpanType.Passive) == (int)LifeSpanType.Passive) { passive_lifeSpans[index_queue] = true; }
// exclusive
if (((int)lifeSpan & (int)LifeSpanType.Exclusive) == (int)LifeSpanType.Exclusive) { exclusive_lifeSpans[index_queue] = true; }
}
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(int index)
{
if (null == m_channels_[index])
{
m_channels_[index] = GetConnection().CreateModel();
// 引数が7つの QueueDeclare でエラーを吐くことがあるので、情報を出力しておく。
Console.Error.WriteLine("GetChannel index = [" + index + "]");
Console.Error.WriteLine(" QUEUE_NAMES[index] = [" + QUEUE_NAMES[index] + "]");
Console.Error.WriteLine(" passive_lifeSpans[index] = [" + passive_lifeSpans[index] + "]");
Console.Error.WriteLine(" durable_lifeSpans[index] = [" + durable_lifeSpans[index] + "]");
Console.Error.WriteLine(" exclusive_lifeSpans[index] = [" + exclusive_lifeSpans[index] + "]");
Console.Error.WriteLine(" autodelete_lifeSpans[index] = [" + autodelete_lifeSpans[index] + "]");
Console.Error.WriteLine(" nowait は仮に false 固定");
Console.Error.WriteLine(" arguments は仮に null 固定");
#if UBUNTU
// Ubuntuでは何故か Spring.Messaging.Amqp.Rabbit の引数 7 つのやつになっている。
m_channels_[index].QueueDeclare(QUEUE_NAMES[index], passive_lifeSpans[index], durable_lifeSpans[index], exclusive_lifeSpans[index], autodelete_lifeSpans[index], false, null);
#else
m_channels_[index].QueueDeclare(QUEUE_NAMES[index], durable_lifeSpans[index], exclusive_lifeSpans[index], autodelete_lifeSpans[index], null);
#endif
}
return m_channels_[index];
}
static IModel[] m_channels_ = new IModel[NUM_INDEX];
public static EventingBasicConsumer GetConsumer(int index)
{
if (null == m_consumers_[index])
{
#if UBUNTU
// Ubuntuでは何故か v1.4.0 の引数が 0 個のやつになっている。調べたが引数が1個~6個のものは無かった。
m_consumers_[index] = new EventingBasicConsumer();
#else
m_consumers_[index] = new EventingBasicConsumer(GetChannel(index));
#endif
}
return m_consumers_[index];
}
static EventingBasicConsumer[] m_consumers_ = new EventingBasicConsumer[NUM_INDEX];
/// <summary>
/// 受信できたときに割り込んでくる処理
/// </summary>
#if UBUNTU
public static BasicDeliverEventHandler GetDequeueHandler()
#else
public static EventHandler<BasicDeliverEventArgs> GetDequeueHandler()
#endif
{
if (null == m_dequeueHandler_)
{
#if UBUNTU
m_dequeueHandler_ = new BasicDeliverEventHandler((model, ea) =>
#else
m_dequeueHandler_ = new EventHandler<BasicDeliverEventArgs>((model, ea) =>
#endif
{
byte[] body = ea.Body;
string message = Encoding.UTF8.GetString(body);
Console.WriteLine("<---- [interrupt!] Dequeue(^q^) {0}", message);
});
}
return m_dequeueHandler_;
}
#if UBUNTU
static BasicDeliverEventHandler m_dequeueHandler_;
#else
static EventHandler<BasicDeliverEventArgs> m_dequeueHandler_;
#endif
/// <summary>
/// 対応するオープンは無いけれど、開けたら閉める、を完璧に対応する必要がある。
/// </summary>
static void CloseConnection()
{
if (null != m_connection_)
{
m_connection_.Close();
m_connection_ = null;
}
}
/// <summary>
/// 対応するオープンは無いけれど、開けたら閉める、を完璧に対応する必要がある。
/// </summary>
static void CloseChannel(int index)
{
if (null != m_channels_[index])
{
m_channels_[index].Close();
m_channels_[index] = null;
}
}
static void Main(string[] args)
{
//----------------------------------------
// Delete
//----------------------------------------
for (;;)
{
Console.Write(@"削除したいキューがあれば名前を、無ければ空文字列を入れろだぜ☆(^~^)
キュー名を入力 : キューを削除します
空文字列で[Enter] : 次のステップへ進む
Name or empty ? > ");
string queueName_delete = Console.ReadLine();
if (""== queueName_delete.Trim())
{
break;
}
Console.Write(@"削除するメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
("+ ((int)LifeSpanType.Durable) + @") durable : RabbitMQが止まってもキューを残す
(" + ((int)LifeSpanType.Autodelete) + @") autodelete : コンシューマーが1人も接続していなかったら消す
(" + ((int)LifeSpanType.Passive) + @") passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(" + ((int)LifeSpanType.Exclusive) + @") exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > ");
LifeSpanType lifeSpan_delete = (LifeSpanType)int.Parse(Console.ReadLine());
SetLifeSpan(DELETEQUEUE_INDEX, queueName_delete, lifeSpan_delete);
uint result = DeleteQueue();
Console.WriteLine(@"["+ queueName_delete + "]キューを削除したはずだぜ☆(^~^) result=["+ result + "]");
}
//----------------------------------------
// Enqueue settings
//----------------------------------------
for (;;)
{
Console.Write(@"エンキュー先のメッセージ・キューの名前を入れろだぜ☆(^~^)
Queue name? > ");
string queueName_enqueue = Console.ReadLine();
Console.Write(@"エンキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(" + ((int)LifeSpanType.Durable) + @") durable : RabbitMQが止まってもキューを残す
(" + ((int)LifeSpanType.Autodelete) + @") autodelete : コンシューマーが1人も接続していなかったら消す
(" + ((int)LifeSpanType.Passive) + @") passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(" + ((int)LifeSpanType.Exclusive) + @") exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > ");
int lifeSpan_enqueue;
if(int.TryParse(Console.ReadLine(),out lifeSpan_enqueue))
{
SetLifeSpan(ENQUEUE_INDEX, queueName_enqueue, (LifeSpanType)lifeSpan_enqueue);
break;
}
}
//----------------------------------------
// Enqueue settings
//----------------------------------------
for (;;)
{
Console.Write(@"デキュー先のメッセージ・キューの名前を入れろだぜ☆(^~^)
Queue name? > ");
string queueName_dequeue = Console.ReadLine();
Console.Write(@"デキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(" + ((int)LifeSpanType.Durable) + @") durable : RabbitMQが止まってもキューを残す
(" + ((int)LifeSpanType.Autodelete) + @") autodelete : コンシューマーが1人も接続していなかったら消す
(" + ((int)LifeSpanType.Passive) + @") passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(" + ((int)LifeSpanType.Exclusive) + @") exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > ");
int lifeSpan_dequeue;
if(int.TryParse(Console.ReadLine(),out lifeSpan_dequeue))
{
StartConsume(queueName_dequeue, (LifeSpanType)lifeSpan_dequeue);
break;
}
}
Console.Write(@"終了するときは[Ctrl]+[C]キーを押せだぜ☆(^~^)
エンキューするときはメッセージを打ち込んで[Enter]キーを押せだぜ☆(^◇^)
Enqueue? > ");
for (;;)
{
// "Hello World!" などを入力
string line = Console.ReadLine();
Enqueue(line);
Console.Write(@"Enqueue? > ");
}
// ここには来ない
// CloseConnection();
}
static uint DeleteQueue()
{
IModel channel = GetChannel(DELETEQUEUE_INDEX);
#if UBUNTU
// Ubuntuでは何故か 昔の .Net 用の引数 5 つのやつの変則版になっている。
// uint QueueDelete(ushort ticket, string queue, bool ifUnused, bool ifEmpty, bool nowait)
uint result = channel.QueueDelete( QUEUE_NAMES[DELETEQUEUE_INDEX],true,true,true);
#else
uint result = channel.QueueDelete(QUEUE_NAMES[DELETEQUEUE_INDEX],true,true);
#endif
// 対応するオープンは無いが、ちゃんと閉じないと、レシーブしてくれない。
CloseChannel(DELETEQUEUE_INDEX);
return result;
}
static void Enqueue(string message)
{
IModel channel = GetChannel(ENQUEUE_INDEX);
byte[] body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish("", QUEUE_NAMES[ENQUEUE_INDEX], null, body);
Console.WriteLine(" Enqueue(^q^) {0}", message);
// 対応するオープンは無いが、ちゃんと閉じないと、レシーブしてくれない。
CloseChannel(ENQUEUE_INDEX);
}
/// <summary>
///
/// </summary>
/// <param name="name_queue">メッセージ・キューの名前</param>
/// <param name="lifeSpan_queue">既存のメッセージ・キューの場合、メッセージ・キューの設定は合わせる必要がある。
/// durable : RabbitMQが止まってもキューを残す
/// autodelete : コンシューマーが1人も接続していなかったら消す
/// passive : キューが存在するかどうかチェックするだけで、中身を見ない時はこれ
/// exclusive : この接続でだけ使える。この接続が切れたら消す
/// </param>
static void StartConsume(string name_queue, LifeSpanType lifeSpan_queue)
{
SetLifeSpan(DEQUEUE_INDEX, name_queue, lifeSpan_queue);
IModel channel = GetChannel(DEQUEUE_INDEX);
EventingBasicConsumer consumer = GetConsumer(DEQUEUE_INDEX);
// 受信できたときに割り込んでくる処理
consumer.Received += GetDequeueHandler();
#if UBUNTU
// Ubuntuでは何故か引数が 5 個のやつになっている。
channel.BasicConsume( QUEUE_NAMES[DEQUEUE_INDEX], true, "", null, consumer);
#else
channel.BasicConsume( QUEUE_NAMES[DEQUEUE_INDEX], true, consumer);
#endif
// 終了はさせない
// consumer.Received -= GetReceiveHandler();
// CloseChannel(DEQUEUE_INDEX);
}
}
}
QueryDeclare の引数は false の方が良かったんだろうか?
#if UBUNTU
// Ubuntuでは何故か Spring.Messaging.Amqp.Rabbit の引数 7 つのやつになっている。
// m_channels_[index].QueueDeclare(QUEUE_NAMES[index], false, false, false, false, false, null);
m_channels_[index].QueueDeclare(QUEUE_NAMES[index], passive_lifeSpans[index], durable_lifeSpans[index], exclusive_lifeSpans[index], autodelete_lifeSpans[index], false, null);
#else
//m_channels_[index].QueueDeclare(QUEUE_NAMES[index], false, false, false, null);
m_channels_[index].QueueDeclare(QUEUE_NAMES[index], durable_lifeSpans[index], exclusive_lifeSpans[index], autodelete_lifeSpans[index], null);
#endif
こんなコードでいいんだろうか?
//--------------------------------------------------------------------------------
// tamesi35a2_cs.cs
//
// メッセージの末尾に daze を付けます。
// 標準入出力は、キーボード、画面には接続しないようにします。
// キューの名前は指定してください。
// デキューは割込みを受け付けます。
//--------------------------------------------------------------------------------
// OS : Windows 10
// IDE : Visual Studio 2015
// Install : NuGet : Install-Package RabbitMQ.Client -Version 4.1.1
//
// OS : Ubuntu 16.04
// Compile : Command : mcs /r:RabbitMQ.Client.dll -define:UBUNTU tamesi35a2_cs.cs
// : Command : // chmod 755 tamesi35a2_cs.cs
// Execute : Command : // バックグラウンドで実行する
// : nohup ./tamesi35a2_cs.exe > ./tamesi35a2_cs.out.log 2> ./tamesi35a2_cs.err.log < /dev/null &
// Check : : // tamesi33a1_cs.exe を使う
//--------------------------------------------------------------------------------
// Ubuntu の RabbitMQ はソースのバージョンが古いのか、API が異なった。
// #define UBUNTU
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Text;
using System.Threading;
/// <summary>
/// このプログラム内だけで使われる数字。AMQP-CPPでの実装とは異なる。
/// AMQP-CPPでの実装 : AMQP::durable=[1] AMQP::autodelete=[2] AMQP::passive=[8] AMQP::exclusive=[512]
/// </summary>
[Flags]
enum LifeSpanType
{
/// <summary>
/// RabbitMQが止まってもキューを残す
/// </summary>
Durable = 1,
/// <summary>
/// コンシューマーが1人も接続していなかったら消す
/// </summary>
Autodelete = 0x1 << 1,
/// <summary>
/// キューが存在するかどうかチェックするだけ。中身見ない時これ
/// </summary>
Passive = 0x1 << 2,
/// <summary>
/// この接続でだけ使える。この接続が切れたら消す
/// </summary>
Exclusive = 0x1 << 3
}
/// <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)
/// 参照 : C#でconstな配列を実現する (もっとクールにプログラミング) http://pgnote.net/?p=885
/// </summary>
class Program
{
const int ENQUEUE_INDEX = 0;
const int DEQUEUE_INDEX = 1;
const int DELETEQUEUE_INDEX = 2;
const int NUM_INDEX = 3;
const string HOST_NAME = "localhost";
static string[] QUEUE_NAMES = new string[NUM_INDEX];
/// <summary>
/// キューの寿命(複合可能)
/// durable : RabbitMQが止まってもキューを残す
/// autodelete : コンシューマーが1人も接続していなかったら消す
/// passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
/// exclusive : この接続でだけ使える。この接続が切れたら消す
/// </summary>
static LifeSpanType[] lifeSpans_queue = new LifeSpanType[NUM_INDEX];
static bool[]
durable_lifeSpans = new bool[NUM_INDEX],
autodelete_lifeSpans = new bool[NUM_INDEX],
passive_lifeSpans = new bool[NUM_INDEX],
exclusive_lifeSpans = new bool[NUM_INDEX];
static void SetLifeSpan(int index_queue, string name_queue, LifeSpanType lifeSpan)
{
QUEUE_NAMES[index_queue] = name_queue;
lifeSpans_queue[index_queue] = lifeSpan;
// 一旦クリアー
durable_lifeSpans[index_queue] = false;
autodelete_lifeSpans[index_queue] = false;
passive_lifeSpans[index_queue] = false;
exclusive_lifeSpans[index_queue] = false;
// durable
if (((int)lifeSpan & (int)LifeSpanType.Durable) == (int)LifeSpanType.Durable) { durable_lifeSpans[index_queue] = true; }
// autodelete
if (((int)lifeSpan & (int)LifeSpanType.Autodelete) == (int)LifeSpanType.Autodelete) { autodelete_lifeSpans[index_queue] = true; }
// passive
if (((int)lifeSpan & (int)LifeSpanType.Passive) == (int)LifeSpanType.Passive) { passive_lifeSpans[index_queue] = true; }
// exclusive
if (((int)lifeSpan & (int)LifeSpanType.Exclusive) == (int)LifeSpanType.Exclusive) { exclusive_lifeSpans[index_queue] = true; }
}
// 回転式バッファー
public static RotationBuffer rollingBuffer = new RotationBuffer();
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 bool IsConnected()
{
if (null != m_connection_)
{
return m_connection_.IsOpen;
}
return false;
}
public static IModel GetChannel(int index)
{
if (null == m_channels_[index])
{
m_channels_[index] = GetConnection().CreateModel();
// 引数が7つの QueueDeclare でエラーを吐くことがあるので、情報を出力しておく。
Console.Error.WriteLine("GetChannel index = [" + index + "]");
Console.Error.WriteLine(" QUEUE_NAMES[index] = [" + QUEUE_NAMES[index] + "]");
Console.Error.WriteLine(" passive_lifeSpans[index] = [" + passive_lifeSpans[index] + "]");
Console.Error.WriteLine(" durable_lifeSpans[index] = [" + durable_lifeSpans[index] + "]");
Console.Error.WriteLine(" exclusive_lifeSpans[index] = [" + exclusive_lifeSpans[index] + "]");
Console.Error.WriteLine(" autodelete_lifeSpans[index] = [" + autodelete_lifeSpans[index] + "]");
Console.Error.WriteLine(" nowait は仮に false 固定");
Console.Error.WriteLine(" arguments は仮に null 固定");
#if UBUNTU
// Ubuntuでは何故か Spring.Messaging.Amqp.Rabbit の引数 7 つのやつになっている。
// m_channels_[index].QueueDeclare(QUEUE_NAMES[index], false, false, false, false, false, null);
m_channels_[index].QueueDeclare(QUEUE_NAMES[index], passive_lifeSpans[index], durable_lifeSpans[index], exclusive_lifeSpans[index], autodelete_lifeSpans[index], false, null);
#else
//m_channels_[index].QueueDeclare(QUEUE_NAMES[index], false, false, false, null);
m_channels_[index].QueueDeclare(QUEUE_NAMES[index], durable_lifeSpans[index], exclusive_lifeSpans[index], autodelete_lifeSpans[index], null);
#endif
}
return m_channels_[index];
}
static IModel[] m_channels_ = new IModel[2];
public static EventingBasicConsumer GetConsumer(int index)
{
if (null == m_consumers_[index])
{
#if UBUNTU
// Ubuntuでは何故か v1.4.0 の引数が 0 個のやつになっている。調べたが引数が1個~6個のものは無かった。
m_consumers_[index] = new EventingBasicConsumer();
#else
m_consumers_[index] = new EventingBasicConsumer(GetChannel(index));
#endif
}
return m_consumers_[index];
}
static EventingBasicConsumer[] m_consumers_ = new EventingBasicConsumer[2];
/// <summary>
/// 受信できたときに割り込んでくる処理
/// </summary>
#if UBUNTU
public static BasicDeliverEventHandler GetDequeueHandler()
#else
public static EventHandler<BasicDeliverEventArgs> GetDequeueHandler()
#endif
{
if (null == m_dequeueHandler_)
{
#if UBUNTU
m_dequeueHandler_ = new BasicDeliverEventHandler((model, ea) =>
#else
m_dequeueHandler_ = new EventHandler<BasicDeliverEventArgs>((model, ea) =>
#endif
{
byte[] body = ea.Body;
string message = Encoding.UTF8.GetString(body);
// 回転式バッファーに入れる
rollingBuffer.PutMessage(message);
});
}
return m_dequeueHandler_;
}
#if UBUNTU
static BasicDeliverEventHandler m_dequeueHandler_;
#else
static EventHandler<BasicDeliverEventArgs> m_dequeueHandler_;
#endif
/// <summary>
/// 対応するオープンは無いけれど、開けたら閉める、を完璧に対応する必要がある。
/// </summary>
static void CloseChannel(int index)
{
if (null != m_channels_[index])
{
m_channels_[index].Close();
m_channels_[index] = null;
}
}
static uint DeleteQueue()
{
IModel channel = GetChannel(DELETEQUEUE_INDEX);
#if UBUNTU
// Ubuntuでは何故か 昔の .Net 用の引数 5 つのやつの変則版になっている。
// uint QueueDelete(ushort ticket, string queue, bool ifUnused, bool ifEmpty, bool nowait)
uint result = channel.QueueDelete( QUEUE_NAMES[DELETEQUEUE_INDEX],true,true,true);
#else
uint result = channel.QueueDelete(QUEUE_NAMES[DELETEQUEUE_INDEX], true, true);
#endif
// 対応するオープンは無いが、ちゃんと閉じないと、レシーブしてくれない。
CloseChannel(DELETEQUEUE_INDEX);
return result;
}
static void Enqueue(string message)
{
// 末尾に daze を付ける。
message += "daze";
IModel channel = GetChannel(ENQUEUE_INDEX);
byte[] body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish("", QUEUE_NAMES[ENQUEUE_INDEX], null, body);
// 対応するオープンは無いが、ちゃんと閉じないと、レシーブしてくれない。
CloseChannel(ENQUEUE_INDEX);
}
static void StartConsume()
{
IModel channel = GetChannel(DEQUEUE_INDEX);
EventingBasicConsumer consumer = GetConsumer(DEQUEUE_INDEX);
// 受信できたときに割り込んでくる処理
consumer.Received += GetDequeueHandler();
#if UBUNTU
// Ubuntuでは何故か引数が 5 個のやつになっている。
channel.BasicConsume( QUEUE_NAMES[DEQUEUE_INDEX], true, "", null, consumer);
#else
channel.BasicConsume(QUEUE_NAMES[DEQUEUE_INDEX], true, consumer);
#endif
// 終了はさせない
// consumer.Received -= GetReceiveHandler();
// CloseChannel(DEQUEUE_INDEX);
}
static void Main(string[] args)
{
//----------------------------------------
// Delete
//----------------------------------------
for (;;)
{
Console.Write(@"削除したいキューがあれば名前を、無ければ空文字列を入れろだぜ☆(^~^)
キュー名を入力 : キューを削除します
空文字列で[Enter] : 次のステップへ進む
Name or empty ? > ");
string queueName_delete = Console.ReadLine();
if ("" == queueName_delete.Trim())
{
break;
}
Console.Write(@"削除するメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(" + ((int)LifeSpanType.Durable) + @") durable : RabbitMQが止まってもキューを残す
(" + ((int)LifeSpanType.Autodelete) + @") autodelete : コンシューマーが1人も接続していなかったら消す
(" + ((int)LifeSpanType.Passive) + @") passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(" + ((int)LifeSpanType.Exclusive) + @") exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > ");
LifeSpanType lifeSpan_delete = (LifeSpanType)int.Parse(Console.ReadLine());
SetLifeSpan(DELETEQUEUE_INDEX, queueName_delete, lifeSpan_delete);
uint result = DeleteQueue();
Console.WriteLine(@"[" + queueName_delete + "]キューを削除したはずだぜ☆(^~^) result=[" + result + "]");
}
//----------------------------------------
// Enqueue settings
//----------------------------------------
for (;;)
{
Console.Write(@"エンキュー先のメッセージ・キューの名前を入れろだぜ☆(^~^)
Queue name? > ");
string queueName_enqueue = Console.ReadLine();
Console.Write(@"エンキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(" + ((int)LifeSpanType.Durable) + @") durable : RabbitMQが止まってもキューを残す
(" + ((int)LifeSpanType.Autodelete) + @") autodelete : コンシューマーが1人も接続していなかったら消す
(" + ((int)LifeSpanType.Passive) + @") passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(" + ((int)LifeSpanType.Exclusive) + @") exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > ");
int lifeSpan_enqueue;
if (int.TryParse(Console.ReadLine(), out lifeSpan_enqueue))
{
SetLifeSpan(ENQUEUE_INDEX, queueName_enqueue, (LifeSpanType)lifeSpan_enqueue);
break;
}
}
//----------------------------------------
// Enqueue settings
//----------------------------------------
for (;;)
{
Console.Write(@"デキュー先のメッセージ・キューの名前を入れろだぜ☆(^~^)
Queue name? > ");
string queueName_dequeue = Console.ReadLine();
Console.Write(@"デキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(" + ((int)LifeSpanType.Durable) + @") durable : RabbitMQが止まってもキューを残す
(" + ((int)LifeSpanType.Autodelete) + @") autodelete : コンシューマーが1人も接続していなかったら消す
(" + ((int)LifeSpanType.Passive) + @") passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(" + ((int)LifeSpanType.Exclusive) + @") exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > ");
int lifeSpan_dequeue;
if (int.TryParse(Console.ReadLine(), out lifeSpan_dequeue))
{
SetLifeSpan(DEQUEUE_INDEX, queueName_dequeue, (LifeSpanType)lifeSpan_dequeue);
StartConsume();
break;
}
}
// 常時監視をスタート
StartConsume();
// 無限ループ
while (IsConnected())
{
string message = rollingBuffer.GetMessage();
if (null != message)
{
// エンキューする
Enqueue(message);
}
Thread.Sleep(20);
}
// このプログラムは、自分では接続を切らない。
}
}
/// <summary>
/// 回転式バッファー。
/// これはメイン・スレッドに置く。
/// デキューのスレッドでエンキューすることはできない。
/// デキュー処理は、回転式バッファーを仲介にしてエンキュー処理にメッセージを渡す。
/// </summary>
public class RotationBuffer
{
public const int bufferSize = 100;
public string[] buffer = new string[bufferSize];
public int[] bufferCursors = new int[] { 0, 0 };
public const int PUT_INDEX = 0;
public const int GET_INDEX = 1;
public void PutMessage(string message)
{
buffer[bufferCursors[PUT_INDEX]] = message;
bufferCursors[PUT_INDEX]++;
if (!(bufferCursors[PUT_INDEX] < bufferSize))
{
bufferCursors[PUT_INDEX] = 0;
}
}
public string GetMessage()
{
if (null != buffer[bufferCursors[GET_INDEX]])
{
string message = buffer[bufferCursors[GET_INDEX]];
buffer[bufferCursors[GET_INDEX]] = null;
bufferCursors[GET_INDEX]++;
if (!(bufferCursors[GET_INDEX] < bufferSize))
{
bufferCursors[GET_INDEX] = 0;
}
return message;
}
return null;
}
}
改造し終わってから気づいたんだが、バックグラウンドで動かすプログラムでは 標準入出力で設定なんかできない。
tamesi35a2_cs.cs コマンドライン引数指定版
こんなんでいいんだろうか?
//--------------------------------------------------------------------------------
// tamesi35a2_cs.cs
//
// メッセージの末尾に daze を付けます。
// 標準入出力は、キーボード、画面には接続しないようにします。
// キューの名前はコマンドライン引数で指定してください。
// デキューは割込みを受け付けます。
//--------------------------------------------------------------------------------
// OS : Windows 10
// IDE : Visual Studio 2015
// Install : NuGet : Install-Package RabbitMQ.Client -Version 4.1.1
//
// OS : Ubuntu 16.04
// Compile : Command : mcs /r:RabbitMQ.Client.dll -define:UBUNTU tamesi35a2_cs.cs
// Execute : Command : // バックグラウンドで実行する
// : nohup ./tamesi35a2_cs.exe --msgqueue 1117 durable 1116 durable > ./tamesi35a2_cs.out.log 2> ./tamesi35a2_cs.err.log < /dev/null &
// Check : : // tamesi33a1_cs.exe を使う
//--------------------------------------------------------------------------------
// Ubuntu の RabbitMQ はソースのバージョンが古いのか、API が異なった。
// #define UBUNTU
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Text;
using System.Threading;
/// <summary>
/// このプログラム内だけで使われる数字。AMQP-CPPでの実装とは異なる。
/// AMQP-CPPでの実装 : AMQP::durable=[1] AMQP::autodelete=[2] AMQP::passive=[8] AMQP::exclusive=[512]
/// </summary>
[Flags]
enum LifeSpanType
{
/// <summary>
/// RabbitMQが止まってもキューを残す
/// </summary>
Durable = 1,
/// <summary>
/// コンシューマーが1人も接続していなかったら消す
/// </summary>
Autodelete = 0x1 << 1,
/// <summary>
/// キューが存在するかどうかチェックするだけ。中身見ない時これ
/// </summary>
Passive = 0x1 << 2,
/// <summary>
/// この接続でだけ使える。この接続が切れたら消す
/// </summary>
Exclusive = 0x1 << 3
}
/// <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)
/// 参照 : C#でconstな配列を実現する (もっとクールにプログラミング) http://pgnote.net/?p=885
/// </summary>
class Program
{
const int ENQUEUE_INDEX = 0;
const int DEQUEUE_INDEX = 1;
const int NUM_INDEX = 2;
const string HOST_NAME = "localhost";
static string[] name_queues = new string[NUM_INDEX];
/// <summary>
/// キューの寿命(複合可能)
/// durable : RabbitMQが止まってもキューを残す
/// autodelete : コンシューマーが1人も接続していなかったら消す
/// passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
/// exclusive : この接続でだけ使える。この接続が切れたら消す
/// </summary>
static LifeSpanType[] lifeSpan_queues = new LifeSpanType[NUM_INDEX];
static LifeSpanType LifeSpanString_To_Enum(string lifeSpan)
{
switch (lifeSpan)
{
case "durable": return LifeSpanType.Durable;
case "autodelete": return LifeSpanType.Autodelete;
case "passive": return LifeSpanType.Passive;
case "exclusive": return LifeSpanType.Exclusive;
default: throw new Exception("未対応のlifeSpan [" + lifeSpan + "]");
}
}
static bool[]
durable_lifeSpans = new bool[NUM_INDEX],
autodelete_lifeSpans = new bool[NUM_INDEX],
passive_lifeSpans = new bool[NUM_INDEX],
exclusive_lifeSpans = new bool[NUM_INDEX];
static void SetLifeSpan(int index_queue, string name_queue, LifeSpanType lifeSpan)
{
name_queues[index_queue] = name_queue;
lifeSpan_queues[index_queue] = lifeSpan;
// 一旦クリアー
durable_lifeSpans[index_queue] = false;
autodelete_lifeSpans[index_queue] = false;
passive_lifeSpans[index_queue] = false;
exclusive_lifeSpans[index_queue] = false;
// durable
if (((int)lifeSpan & (int)LifeSpanType.Durable) == (int)LifeSpanType.Durable) { durable_lifeSpans[index_queue] = true; }
// autodelete
if (((int)lifeSpan & (int)LifeSpanType.Autodelete) == (int)LifeSpanType.Autodelete) { autodelete_lifeSpans[index_queue] = true; }
// passive
if (((int)lifeSpan & (int)LifeSpanType.Passive) == (int)LifeSpanType.Passive) { passive_lifeSpans[index_queue] = true; }
// exclusive
if (((int)lifeSpan & (int)LifeSpanType.Exclusive) == (int)LifeSpanType.Exclusive) { exclusive_lifeSpans[index_queue] = true; }
}
// 回転式バッファー
static RotationBuffer rollingBuffer = new RotationBuffer();
static ConnectionFactory GetFactory()
{
if (null == m_factory_)
{
m_factory_ = new ConnectionFactory() { HostName = HOST_NAME };
}
return m_factory_;
}
static ConnectionFactory m_factory_;
static IConnection GetConnection()
{
if (null == m_connection_)
{
m_connection_ = GetFactory().CreateConnection();
}
return m_connection_;
}
static IConnection m_connection_;
static bool IsConnected()
{
if (null != m_connection_)
{
return m_connection_.IsOpen;
}
return false;
}
static IModel GetChannel(int index)
{
if (null == m_channels_[index])
{
m_channels_[index] = GetConnection().CreateModel();
// 引数が7つの QueueDeclare でエラーを吐くことがあるので、情報を出力しておく。
Console.Error.WriteLine("GetChannel index = [" + index + "]");
Console.Error.WriteLine(" QUEUE_NAMES[index] = [" + name_queues[index] + "]");
Console.Error.WriteLine(" passive_lifeSpans[index] = [" + passive_lifeSpans[index] + "]");
Console.Error.WriteLine(" durable_lifeSpans[index] = [" + durable_lifeSpans[index] + "]");
Console.Error.WriteLine(" exclusive_lifeSpans[index] = [" + exclusive_lifeSpans[index] + "]");
Console.Error.WriteLine(" autodelete_lifeSpans[index] = [" + autodelete_lifeSpans[index] + "]");
Console.Error.WriteLine(" nowait は仮に false 固定");
Console.Error.WriteLine(" arguments は仮に null 固定");
#if UBUNTU
// Ubuntuでは何故か Spring.Messaging.Amqp.Rabbit の引数 7 つのやつになっている。
// m_channels_[index].QueueDeclare(QUEUE_NAMES[index], false, false, false, false, false, null);
m_channels_[index].QueueDeclare(QUEUE_NAMES[index], passive_lifeSpans[index], durable_lifeSpans[index], exclusive_lifeSpans[index], autodelete_lifeSpans[index], false, null);
#else
//m_channels_[index].QueueDeclare(QUEUE_NAMES[index], false, false, false, null);
m_channels_[index].QueueDeclare(name_queues[index], durable_lifeSpans[index], exclusive_lifeSpans[index], autodelete_lifeSpans[index], null);
#endif
}
return m_channels_[index];
}
static IModel[] m_channels_ = new IModel[2];
static EventingBasicConsumer GetConsumer(int index)
{
if (null == m_consumers_[index])
{
#if UBUNTU
// Ubuntuでは何故か v1.4.0 の引数が 0 個のやつになっている。調べたが引数が1個~6個のものは無かった。
m_consumers_[index] = new EventingBasicConsumer();
#else
m_consumers_[index] = new EventingBasicConsumer(GetChannel(index));
#endif
}
return m_consumers_[index];
}
static EventingBasicConsumer[] m_consumers_ = new EventingBasicConsumer[2];
/// <summary>
/// 受信できたときに割り込んでくる処理
/// </summary>
#if UBUNTU
public static BasicDeliverEventHandler GetDequeueHandler()
#else
static EventHandler<BasicDeliverEventArgs> GetDequeueHandler()
#endif
{
if (null == m_dequeueHandler_)
{
#if UBUNTU
m_dequeueHandler_ = new BasicDeliverEventHandler((model, ea) =>
#else
m_dequeueHandler_ = new EventHandler<BasicDeliverEventArgs>((model, ea) =>
#endif
{
byte[] body = ea.Body;
string message = Encoding.UTF8.GetString(body);
// 回転式バッファーに入れる
rollingBuffer.PutMessage(message);
});
}
return m_dequeueHandler_;
}
#if UBUNTU
static BasicDeliverEventHandler m_dequeueHandler_;
#else
static EventHandler<BasicDeliverEventArgs> m_dequeueHandler_;
#endif
/// <summary>
/// 対応するオープンは無いけれど、開けたら閉める、を完璧に対応する必要がある。
/// </summary>
static void CloseChannel(int index)
{
if (null != m_channels_[index])
{
m_channels_[index].Close();
m_channels_[index] = null;
}
}
static void Enqueue(string message)
{
// 末尾に daze を付ける。
message += "daze";
IModel channel = GetChannel(ENQUEUE_INDEX);
byte[] body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish("", name_queues[ENQUEUE_INDEX], null, body);
// 対応するオープンは無いが、ちゃんと閉じないと、レシーブしてくれない。
CloseChannel(ENQUEUE_INDEX);
}
static void StartConsume()
{
IModel channel = GetChannel(DEQUEUE_INDEX);
EventingBasicConsumer consumer = GetConsumer(DEQUEUE_INDEX);
// 受信できたときに割り込んでくる処理
consumer.Received += GetDequeueHandler();
#if UBUNTU
// Ubuntuでは何故か引数が 5 個のやつになっている。
channel.BasicConsume( QUEUE_NAMES[DEQUEUE_INDEX], true, "", null, consumer);
#else
channel.BasicConsume(name_queues[DEQUEUE_INDEX], true, consumer);
#endif
// 終了はさせない
// consumer.Received -= GetReceiveHandler();
// CloseChannel(DEQUEUE_INDEX);
}
static void Main(string[] args)
{
if (args.Length<1)
{
goto gt_Error1;
}
// 引数の解析
{
// 与件
// 「--msgqueue 1117 durable 1116 durable」という引数は「--msgqueue」「1117」「durable」「1116」「durable」に分解される。
// 受け皿
// 0:enqueue 1:dequeue
// 記憶
int m0 = 0; // カーソル相当
// 解析器
foreach (string a in args)
{
if (m0==0)
{
switch (a)
{
case "--msgqueue": m0++; break;
default: goto gt_Error1;
}
}
else //--msgqueue 内容
{
switch ((m0 - 1) % 2) // 引数名の分1引いている
{
case 0: name_queues[(m0 - 1) / 2] = a; m0++; break;
case 1: lifeSpan_queues[(m0 - 1) / 2] = LifeSpanString_To_Enum(a); m0++; break;
}
}
}
// 結果
for (int i = 0; i < 2; i++)
{
SetLifeSpan(i, name_queues[i], lifeSpan_queues[i]);
}
}
// 常時監視をスタート
StartConsume();
// 無限ループ
while (IsConnected())
{
string message = rollingBuffer.GetMessage();
if (null != message)
{
// エンキューする
Enqueue(message);
}
Thread.Sleep(20);
}
// このプログラムは、自分では接続を切らない。
return;
gt_Error1:
throw new Exception(@"コマンドライン引数に「--msgqueue キュー名 寿命 キュー名 寿命」を指定しろだぜ☆(^~^)
エンキュー先、デキュー先の順番な☆(^▽^)
寿命は durable, autodelete, passive, exclusive のいずれかで、
複合指定にはまだ対応していないぜ☆(>_<)");
}
}
/// <summary>
/// 回転式バッファー。
/// これはメイン・スレッドに置く。
/// デキューのスレッドでエンキューすることはできない。
/// デキュー処理は、回転式バッファーを仲介にしてエンキュー処理にメッセージを渡す。
/// </summary>
public class RotationBuffer
{
public const int bufferSize = 100;
public string[] buffer = new string[bufferSize];
public int[] bufferCursors = new int[] { 0, 0 };
public const int PUT_INDEX = 0;
public const int GET_INDEX = 1;
public void PutMessage(string message)
{
buffer[bufferCursors[PUT_INDEX]] = message;
bufferCursors[PUT_INDEX]++;
if (!(bufferCursors[PUT_INDEX] < bufferSize))
{
bufferCursors[PUT_INDEX] = 0;
}
}
public string GetMessage()
{
if (null != buffer[bufferCursors[GET_INDEX]])
{
string message = buffer[bufferCursors[GET_INDEX]];
buffer[bufferCursors[GET_INDEX]] = null;
bufferCursors[GET_INDEX]++;
if (!(bufferCursors[GET_INDEX] < bufferSize))
{
bufferCursors[GET_INDEX] = 0;
}
return message;
}
return null;
}
}
そういえば今まで標準入力を捨ててなかった気がするな。
./tamesi35a2_cs.exe --msgqueue 1117 durable 1116 durable > ./tamesi35a2_cs.out.log 2> ./tamesi35a2_cs.err.log < /dev/null &
# ./tamesi34_cs.exe
削除したいキューがあれば名前を、無ければ空文字列を入れろだぜ☆(^~^)
キュー名を入力 : キューを削除します
空文字列で[Enter] : 次のステップへ進む
Name or empty ? >
エンキュー先のメッセージ・キューの名前を入れろだぜ☆(^~^)
Queue name? > 1116
エンキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(1) durable : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが1人も接続していなかったら消す
(4) passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > 0
デキュー先のメッセージ・キューの名前を入れろだぜ☆(^~^)
Queue name? > 1117
デキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(1) durable : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが1人も接続していなかったら消す
(4) passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > 0
GetChannel index = [1]
QUEUE_NAMES[index] = [1117]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [False]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [False]
nowait は仮に false 固定
arguments は仮に null 固定
Unhandled Exception:
RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=406, text="PRECONDITION_FAILED - inequivalent arg 'durable' for queue '1117' in vhost '/': received 'false' but current is 'true'", classId=50, methodId=10, cause=
at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply () <0x4013c420 + 0x00107> in <filename unknown>:0
at RabbitMQ.Client.Impl.ModelBase.ModelRpc (RabbitMQ.Client.Impl.MethodBase method, RabbitMQ.Client.Impl.ContentHeaderBase header, System.Byte[] body) <0x4013a290 + 0x000fd> in <filename unknown>:0
at RabbitMQ.Client.Framing.Impl.v0_8.Model.QueueDeclare (System.String queue, Boolean passive, Boolean durable, Boolean exclusive, Boolean autoDelete, Boolean nowait, IDictionary arguments) <0x4013e6d0 + 0x00113> in <filename unknown>:0
at UsagiMQ.Program.GetChannel (Int32 index) <0x400ffd20 + 0x00436> in <filename unknown>:0
at UsagiMQ.Program.StartConsume (System.String name_queue, LifeSpanType lifeSpan_queue) <0x400ffc40 + 0x0002b> in <filename unknown>:0
at UsagiMQ.Program.Main (System.String[] args) <0x400fad50 + 0x0096b> in <filename unknown>:0
[ERROR] FATAL UNHANDLED EXCEPTION: RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=406, text="PRECONDITION_FAILED - inequivalent arg 'durable' for queue '1117' in vhost '/': received 'false' but current is 'true'", classId=50, methodId=10, cause=
at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply () <0x4013c420 + 0x00107> in <filename unknown>:0
at RabbitMQ.Client.Impl.ModelBase.ModelRpc (RabbitMQ.Client.Impl.MethodBase method, RabbitMQ.Client.Impl.ContentHeaderBase header, System.Byte[] body) <0x4013a290 + 0x000fd> in <filename unknown>:0
at RabbitMQ.Client.Framing.Impl.v0_8.Model.QueueDeclare (System.String queue, Boolean passive, Boolean durable, Boolean exclusive, Boolean autoDelete, Boolean nowait, IDictionary arguments) <0x4013e6d0 + 0x00113> in <filename unknown>:0
at UsagiMQ.Program.GetChannel (Int32 index) <0x400ffd20 + 0x00436> in <filename unknown>:0
at UsagiMQ.Program.StartConsume (System.String name_queue, LifeSpanType lifeSpan_queue) <0x400ffc40 + 0x0002b> in <filename unknown>:0
at UsagiMQ.Program.Main (System.String[] args) <0x400fad50 + 0x0096b> in <filename unknown>:0
チャンネル宣言の引数が4つfalse なのもおかしい。もっと情報を出そう。
Visual Studio 2015 で tamesi34_cs.cs を動かしてみた
削除したいキューがあれば名前を、無ければ空文字列を入れろだぜ☆(^~^)
キュー名を入力 : キューを削除します
空文字列で[Enter] : 次のステップへ進む
Name or empty ? >
エンキュー先のメッセージ・キューの名前を入れろだぜ☆(^~^)
Queue name? > 1117
エンキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(1) durable : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが1人も接続していなかったら消す
(4) passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > 0
デキュー先のメッセージ・キューの名前を入れろだぜ☆(^~^)
Queue name? > 1116
デキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(1) durable : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが1人も接続していなかったら消す
(4) passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > 0
tamesi34_cs.cs Dump
name_queues [ENQUEUE_INDEX] =[1117]
lifeSpan_queues [ENQUEUE_INDEX] =[0]
durable_lifeSpans [ENQUEUE_INDEX] =[False]
autodelete_lifeSpans[ENQUEUE_INDEX] =[False]
passive_lifeSpans [ENQUEUE_INDEX] =[False]
exclusive_lifeSpans [ENQUEUE_INDEX] =[False]
----
name_queues [DEQUEUE_INDEX] =[1116]
lifeSpan_queues [DEQUEUE_INDEX] =[0]
durable_lifeSpans [DEQUEUE_INDEX] =[False]
autodelete_lifeSpans[DEQUEUE_INDEX] =[False]
passive_lifeSpans [DEQUEUE_INDEX] =[False]
exclusive_lifeSpans [DEQUEUE_INDEX] =[False]
----
name_queues [DELETEQUEUE_INDEX]=[]
lifeSpan_queues [DELETEQUEUE_INDEX]=[0]
durable_lifeSpans [DELETEQUEUE_INDEX]=[False]
autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
passive_lifeSpans [DELETEQUEUE_INDEX]=[False]
exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
----
(tamesi34_cs.cs?) GetChannel index = [1]
name_queues[index] = [1116]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [False]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [False]
nowait は仮に false 固定
arguments は仮に null 固定
おかしいじゃないか。false が4つ入っている。
あっ! durable、0スタートじゃなくて 1スタートに変えたんだった!
削除したいキューがあれば名前を、無ければ空文字列を入れろだぜ☆(^~^)
キュー名を入力 : キューを削除します
空文字列で[Enter] : 次のステップへ進む
Name or empty ? >
エンキュー先のメッセージ・キューの名前を入れろだぜ☆(^~^)
Queue name? > 1117
エンキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(1) durable : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが1人も接続していなかったら消す
(4) passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > 1
デキュー先のメッセージ・キューの名前を入れろだぜ☆(^~^)
Queue name? > 1116
デキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(1) durable : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが1人も接続していなかったら消す
(4) passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > 1
tamesi34_cs.cs Dump
name_queues [ENQUEUE_INDEX] =[1117]
lifeSpan_queues [ENQUEUE_INDEX] =[Durable]
durable_lifeSpans [ENQUEUE_INDEX] =[True]
autodelete_lifeSpans[ENQUEUE_INDEX] =[False]
passive_lifeSpans [ENQUEUE_INDEX] =[False]
exclusive_lifeSpans [ENQUEUE_INDEX] =[False]
----
name_queues [DEQUEUE_INDEX] =[1116]
lifeSpan_queues [DEQUEUE_INDEX] =[Durable]
durable_lifeSpans [DEQUEUE_INDEX] =[True]
autodelete_lifeSpans[DEQUEUE_INDEX] =[False]
passive_lifeSpans [DEQUEUE_INDEX] =[False]
exclusive_lifeSpans [DEQUEUE_INDEX] =[False]
----
name_queues [DELETEQUEUE_INDEX]=[]
lifeSpan_queues [DELETEQUEUE_INDEX]=[0]
durable_lifeSpans [DELETEQUEUE_INDEX]=[False]
autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
passive_lifeSpans [DELETEQUEUE_INDEX]=[False]
exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
----
(tamesi34_cs.cs?) GetChannel index = [1]
name_queues[index] = [1116]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [False]
nowait は仮に false 固定
arguments は仮に null 固定
終了するときは[Ctrl]+[C]キーを押せだぜ☆(^~^)
エンキューするときはメッセージを打ち込んで[Enter]キーを押せだぜ☆(^◇^)
Enqueue? >
ここまでは おっけー。
# ./tamesi35a2_cs.exe --msgqueue 1117 durable 1116 durable > ./tamesi35a2_cs.out.log 2> ./tamesi35a2_cs.err.log < /dev/null &
[1] 24403
# ./tamesi34_cs.exe
削除したいキューがあれば名前を、無ければ空文字列を入れろだぜ☆(^~^)
キュー名を入力 : キューを削除します
空文字列で[Enter] : 次のステップへ進む
Name or empty ? >
エンキュー先のメッセージ・キューの名前を入れろだぜ☆(^~^)
Queue name? > 1116
エンキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(1) durable : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが1人も接続していなかったら消す
(4) passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > 1
デキュー先のメッセージ・キューの名前を入れろだぜ☆(^~^)
Queue name? > 1117
デキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(1) durable : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが1人も接続していなかったら消す
(4) passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > 1
GetChannel index = [1]
QUEUE_NAMES[index] = [1117]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [False]
nowait は仮に false 固定
arguments は仮に null 固定
終了するときは[Ctrl]+[C]キーを押せだぜ☆(^~^)
エンキューするときはメッセージを打ち込んで[Enter]キーを押せだぜ☆(^◇^)
Enqueue? >
1 にしたら、動いてるじゃないか。
Enqueue? > kame
GetChannel index = [0]
QUEUE_NAMES[index] = [1116]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [False]
nowait は仮に false 固定
arguments は仮に null 固定
Unhandled Exception:
RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=406, text="PRECONDITION_FAILED - inequivalent arg 'durable' for queue '1116' in vhost '/': received 'true' but current is 'false'", classId=50, methodId=10, cause=
at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply () <0x42014f00 + 0x00103> in <filename unknown>:0
at RabbitMQ.Client.Impl.ModelBase.ModelRpc (RabbitMQ.Client.Impl.MethodBase method, RabbitMQ.Client.Impl.ContentHeaderBase header, System.Byte[] body) <0x42012d90 + 0x000f9> in <filename unknown>:0
at RabbitMQ.Client.Framing.Impl.v0_8.Model.QueueDeclare (System.String queue, Boolean passive, Boolean durable, Boolean exclusive, Boolean autoDelete, Boolean nowait, IDictionary arguments) <0x420171d0 + 0x00113> in <filename unknown>:0
at UsagiMQ.Program.GetChannel (Int32 index) <0x41fd88d0 + 0x00436> in <filename unknown>:0
at UsagiMQ.Program.Enqueue (System.String message) <0x420182e0 + 0x00013> in <filename unknown>:0
at UsagiMQ.Program.Main (System.String[] args) <0x41fd3d50 + 0x0099f> in <filename unknown>:0
[ERROR] FATAL UNHANDLED EXCEPTION: RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=406, text="PRECONDITION_FAILED - inequivalent arg 'durable' for queue '1116' in vhost '/': received 'true' but current is 'false'", classId=50, methodId=10, cause=
at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply () <0x42014f00 + 0x00103> in <filename unknown>:0
at RabbitMQ.Client.Impl.ModelBase.ModelRpc (RabbitMQ.Client.Impl.MethodBase method, RabbitMQ.Client.Impl.ContentHeaderBase header, System.Byte[] body) <0x42012d90 + 0x000f9> in <filename unknown>:0
at RabbitMQ.Client.Framing.Impl.v0_8.Model.QueueDeclare (System.String queue, Boolean passive, Boolean durable, Boolean exclusive, Boolean autoDelete, Boolean nowait, IDictionary arguments) <0x420171d0 + 0x00113> in <filename unknown>:0
at UsagiMQ.Program.GetChannel (Int32 index) <0x41fd88d0 + 0x00436> in <filename unknown>:0
at UsagiMQ.Program.Enqueue (System.String message) <0x420182e0 + 0x00013> in <filename unknown>:0
at UsagiMQ.Program.Main (System.String[] args) <0x41fd3d50 + 0x0099f> in <filename unknown>:0
[1]+ Exit 1 ./tamesi35a2_cs.exe --msgqueue 1117 durable 1116 durable > ./tamesi35a2_cs.out.log 2> ./tamesi35a2_cs.err.log < /dev/null
動いてないぜ。
PRECONDITION_FAILED - inequivalent arg 'durable' for queue '1116' in vhost '/': received 'true' but current is 'false'
こういうエラーなんだろうけど。
じゃあ false にしたらいいのか?
あるいは エンキューを別スレッドにするのが まだ残っている
その前に Visual Studio 2015 でやったら
tamesi34_cs.exe
削除したいキューがあれば名前を、無ければ空文字列を入れろだぜ☆(^~^)
キュー名を入力 : キューを削除します
空文字列で[Enter] : 次のステップへ進む
Name or empty ? >
エンキュー先のメッセージ・キューの名前を入れろだぜ☆(^~^)
Queue name? > 1116
エンキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(1) durable : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが1人も接続していなかったら消す
(4) passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > 1
デキュー先のメッセージ・キューの名前を入れろだぜ☆(^~^)
Queue name? > 1117
デキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(1) durable : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが1人も接続していなかったら消す
(4) passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > 1
tamesi34_cs.cs Dump
name_queues [ENQUEUE_INDEX] =[1116]
lifeSpan_queues [ENQUEUE_INDEX] =[Durable]
durable_lifeSpans [ENQUEUE_INDEX] =[True]
autodelete_lifeSpans[ENQUEUE_INDEX] =[False]
passive_lifeSpans [ENQUEUE_INDEX] =[False]
exclusive_lifeSpans [ENQUEUE_INDEX] =[False]
----
name_queues [DEQUEUE_INDEX] =[1117]
lifeSpan_queues [DEQUEUE_INDEX] =[Durable]
durable_lifeSpans [DEQUEUE_INDEX] =[True]
autodelete_lifeSpans[DEQUEUE_INDEX] =[False]
passive_lifeSpans [DEQUEUE_INDEX] =[False]
exclusive_lifeSpans [DEQUEUE_INDEX] =[False]
----
name_queues [DELETEQUEUE_INDEX]=[]
lifeSpan_queues [DELETEQUEUE_INDEX]=[0]
durable_lifeSpans [DELETEQUEUE_INDEX]=[False]
autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
passive_lifeSpans [DELETEQUEUE_INDEX]=[False]
exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
----
(tamesi34_cs.cs?) GetChannel index = [1]
name_queues[index] = [1117]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [False]
nowait は仮に false 固定
arguments は仮に null 固定
終了するときは[Ctrl]+[C]キーを押せだぜ☆(^~^)
エンキューするときはメッセージを打ち込んで[Enter]キーを押せだぜ☆(^◇^)
Enqueue? > usi
tamesi34_cs.cs Dump
name_queues [ENQUEUE_INDEX] =[1116]
lifeSpan_queues [ENQUEUE_INDEX] =[Durable]
durable_lifeSpans [ENQUEUE_INDEX] =[True]
autodelete_lifeSpans[ENQUEUE_INDEX] =[False]
passive_lifeSpans [ENQUEUE_INDEX] =[False]
exclusive_lifeSpans [ENQUEUE_INDEX] =[False]
----
name_queues [DEQUEUE_INDEX] =[1117]
lifeSpan_queues [DEQUEUE_INDEX] =[Durable]
durable_lifeSpans [DEQUEUE_INDEX] =[True]
autodelete_lifeSpans[DEQUEUE_INDEX] =[False]
passive_lifeSpans [DEQUEUE_INDEX] =[False]
exclusive_lifeSpans [DEQUEUE_INDEX] =[False]
----
name_queues [DELETEQUEUE_INDEX]=[]
lifeSpan_queues [DELETEQUEUE_INDEX]=[0]
durable_lifeSpans [DELETEQUEUE_INDEX]=[False]
autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
passive_lifeSpans [DELETEQUEUE_INDEX]=[False]
exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
----
(tamesi34_cs.cs?) GetChannel index = [0]
name_queues[index] = [1116]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [False]
nowait は仮に false 固定
arguments は仮に null 固定
Enqueue(^q^) usi
Enqueue? > <---- [interrupt!] Dequeue(^q^) usidaze
neko
tamesi34_cs.cs Dump
name_queues [ENQUEUE_INDEX] =[1116]
lifeSpan_queues [ENQUEUE_INDEX] =[Durable]
durable_lifeSpans [ENQUEUE_INDEX] =[True]
autodelete_lifeSpans[ENQUEUE_INDEX] =[False]
passive_lifeSpans [ENQUEUE_INDEX] =[False]
exclusive_lifeSpans [ENQUEUE_INDEX] =[False]
----
name_queues [DEQUEUE_INDEX] =[1117]
lifeSpan_queues [DEQUEUE_INDEX] =[Durable]
durable_lifeSpans [DEQUEUE_INDEX] =[True]
autodelete_lifeSpans[DEQUEUE_INDEX] =[False]
passive_lifeSpans [DEQUEUE_INDEX] =[False]
exclusive_lifeSpans [DEQUEUE_INDEX] =[False]
----
name_queues [DELETEQUEUE_INDEX]=[]
lifeSpan_queues [DELETEQUEUE_INDEX]=[0]
durable_lifeSpans [DELETEQUEUE_INDEX]=[False]
autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
passive_lifeSpans [DELETEQUEUE_INDEX]=[False]
exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
----
(tamesi34_cs.cs?) GetChannel index = [0]
name_queues[index] = [1116]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [False]
nowait は仮に false 固定
arguments は仮に null 固定
Enqueue(^q^) neko
Enqueue? > <---- [interrupt!] Dequeue(^q^) nekodaze
zou
tamesi34_cs.cs Dump
name_queues [ENQUEUE_INDEX] =[1116]
lifeSpan_queues [ENQUEUE_INDEX] =[Durable]
durable_lifeSpans [ENQUEUE_INDEX] =[True]
autodelete_lifeSpans[ENQUEUE_INDEX] =[False]
passive_lifeSpans [ENQUEUE_INDEX] =[False]
exclusive_lifeSpans [ENQUEUE_INDEX] =[False]
----
name_queues [DEQUEUE_INDEX] =[1117]
lifeSpan_queues [DEQUEUE_INDEX] =[Durable]
durable_lifeSpans [DEQUEUE_INDEX] =[True]
autodelete_lifeSpans[DEQUEUE_INDEX] =[False]
passive_lifeSpans [DEQUEUE_INDEX] =[False]
exclusive_lifeSpans [DEQUEUE_INDEX] =[False]
----
name_queues [DELETEQUEUE_INDEX]=[]
lifeSpan_queues [DELETEQUEUE_INDEX]=[0]
durable_lifeSpans [DELETEQUEUE_INDEX]=[False]
autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
passive_lifeSpans [DELETEQUEUE_INDEX]=[False]
exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
----
(tamesi34_cs.cs?) GetChannel index = [0]
name_queues[index] = [1116]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [False]
nowait は仮に false 固定
arguments は仮に null 固定
Enqueue(^q^) zou
Enqueue? > <---- [interrupt!] Dequeue(^q^) zoudaze
tamesi35a2_cs.exe
(0) name=[1117] lifeSpan=[Durable]
(1) name=[1116] lifeSpan=[Durable]
(tamesi35a2_cs.cs?) GetChannel index = [1]
name_queues[index] = [1116]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [False]
nowait は仮に false 固定
arguments は仮に null 固定
(tamesi35a2_cs.cs?) GetChannel index = [0]
name_queues[index] = [1117]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [False]
nowait は仮に false 固定
arguments は仮に null 固定
(tamesi35a2_cs.cs?) GetChannel index = [0]
name_queues[index] = [1117]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [False]
nowait は仮に false 固定
arguments は仮に null 固定
(tamesi35a2_cs.cs?) GetChannel index = [0]
name_queues[index] = [1117]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [False]
nowait は仮に false 固定
arguments は仮に null 固定
Windows10 なら動いてるのにな。
これを Ubuntu16.04 で実行すると
root@tk2-217-18401:/home/★user/shogi/csharp_service# rm tamesi34_cs.cs
root@tk2-217-18401:/home/★user/shogi/csharp_service# nano tamesi34_cs.cs
root@tk2-217-18401:/home/★user/shogi/csharp_service# rm tamesi35a2_cs.cs
root@tk2-217-18401:/home/★user/shogi/csharp_service# nano tamesi35a2_cs.cs
root@tk2-217-18401:/home/★user/shogi/csharp_service# mcs /r:RabbitMQ.Client.dll -define:UBUNTU tamesi34_cs.cs
root@tk2-217-18401:/home/★user/shogi/csharp_service# mcs /r:RabbitMQ.Client.dll -define:UBUNTU tamesi35a2_cs.cs
root@tk2-217-18401:/home/★user/shogi/csharp_service# ./tamesi35a2_cs.exe --msgqueue 1117 durable 1116 durable > ./tamesi35a2_cs.out.log 2> ./tamesi35a2_cs.err.log < /dev/null &
[1] 31008
root@tk2-217-18401:/home/★user/shogi/csharp_service# ./tamesi34_cs.exe 2> ./tamesi34_cs.err.log
削除したいキューがあれば名前を、無ければ空文字列を入れろだぜ☆(^~^)
キュー名を入力 : キューを削除します
空文字列で[Enter] : 次のステップへ進む
Name or empty ? >
エンキュー先のメッセージ・キューの名前を入れろだぜ☆(^~^)
Queue name? > 1116
エンキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(1) durable : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが1人も接続していなかったら消す
(4) passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > 1
デキュー先のメッセージ・キューの名前を入れろだぜ☆(^~^)
Queue name? > 1117
デキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(1) durable : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが1人も接続していなかったら消す
(4) passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > 1
tamesi34_cs.cs Dump
name_queues [ENQUEUE_INDEX] =[1116]
lifeSpan_queues [ENQUEUE_INDEX] =[Durable]
durable_lifeSpans [ENQUEUE_INDEX] =[True]
autodelete_lifeSpans[ENQUEUE_INDEX] =[False]
passive_lifeSpans [ENQUEUE_INDEX] =[False]
exclusive_lifeSpans [ENQUEUE_INDEX] =[False]
----
name_queues [DEQUEUE_INDEX] =[1117]
lifeSpan_queues [DEQUEUE_INDEX] =[Durable]
durable_lifeSpans [DEQUEUE_INDEX] =[True]
autodelete_lifeSpans[DEQUEUE_INDEX] =[False]
passive_lifeSpans [DEQUEUE_INDEX] =[False]
exclusive_lifeSpans [DEQUEUE_INDEX] =[False]
----
name_queues [DELETEQUEUE_INDEX]=[]
lifeSpan_queues [DELETEQUEUE_INDEX]=[0]
durable_lifeSpans [DELETEQUEUE_INDEX]=[False]
autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
passive_lifeSpans [DELETEQUEUE_INDEX]=[False]
exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
----
(tamesi34_cs.cs?) GetChannel index = [1]
name_queues[index] = [1117]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [False]
nowait は仮に false 固定
arguments は仮に null 固定
終了するときは[Ctrl]+[C]キーを押せだぜ☆(^~^)
エンキューするときはメッセージを打ち込んで[Enter]キーを押せだぜ☆(^◇^)
Enqueue? > usi
tamesi34_cs.cs Dump
name_queues [ENQUEUE_INDEX] =[1116]
lifeSpan_queues [ENQUEUE_INDEX] =[Durable]
durable_lifeSpans [ENQUEUE_INDEX] =[True]
autodelete_lifeSpans[ENQUEUE_INDEX] =[False]
passive_lifeSpans [ENQUEUE_INDEX] =[False]
exclusive_lifeSpans [ENQUEUE_INDEX] =[False]
----
name_queues [DEQUEUE_INDEX] =[1117]
lifeSpan_queues [DEQUEUE_INDEX] =[Durable]
durable_lifeSpans [DEQUEUE_INDEX] =[True]
autodelete_lifeSpans[DEQUEUE_INDEX] =[False]
passive_lifeSpans [DEQUEUE_INDEX] =[False]
exclusive_lifeSpans [DEQUEUE_INDEX] =[False]
----
name_queues [DELETEQUEUE_INDEX]=[]
lifeSpan_queues [DELETEQUEUE_INDEX]=[0]
durable_lifeSpans [DELETEQUEUE_INDEX]=[False]
autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
passive_lifeSpans [DELETEQUEUE_INDEX]=[False]
exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
----
(tamesi34_cs.cs?) GetChannel index = [0]
name_queues[index] = [1116]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [False]
nowait は仮に false 固定
arguments は仮に null 固定
[1]+ Exit 1 ./tamesi35a2_cs.exe --msgqueue 1117 durable 1116 durable > ./tamesi35a2_cs.out.log 2> ./tamesi35a2_cs.err.log < /dev/null
プログラム以外の理由で落ちてるのか?
# rabbitmq-server
ERROR: node with name "rabbit" already running on "tk2-217-18401"
# nano tamesi34_cs.err.log
Unhandled Exception:
RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=406, text="PRECONDITION_FAILED - inequivalent arg 'durable' for queue '1116' in vhost '/': receiv$
at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply () <0x40d35fd0 + 0x00103> in <filename unknown>:0
at RabbitMQ.Client.Impl.ModelBase.ModelRpc (RabbitMQ.Client.Impl.MethodBase method, RabbitMQ.Client.Impl.ContentHeaderBase header, System.Byte[] body) <0x40d33da0 + 0x000f9> in <filename unknown>:0
at RabbitMQ.Client.Framing.Impl.v0_8.Model.QueueDeclare (System.String queue, Boolean passive, Boolean durable, Boolean exclusive, Boolean autoDelete, Boolean nowait, IDictionary arguments) <0x40d38f30 + 0x00113> in <filename unknow$
at UsagiMQ.Program.GetChannel (Int32 index) <0x40cf98c0 + 0x0045c> in <filename unknown>:0
at UsagiMQ.Program.Enqueue (System.String message) <0x40d3a030 + 0x00013> in <filename unknown>:0
at UsagiMQ.Program.Main (System.String[] args) <0x40cf4d50 + 0x009a7> in <filename unknown>:0
[ERROR] FATAL UNHANDLED EXCEPTION: RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=406, text="PRECONDITION_FAILED - inequivalent arg 'durable' fo$
at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply () <0x40d35fd0 + 0x00103> in <filename unknown>:0
at RabbitMQ.Client.Impl.ModelBase.ModelRpc (RabbitMQ.Client.Impl.MethodBase method, RabbitMQ.Client.Impl.ContentHeaderBase header, System.Byte[] body) <0x40d33da0 + 0x000f9> in <filename unknown>:0
at RabbitMQ.Client.Framing.Impl.v0_8.Model.QueueDeclare (System.String queue, Boolean passive, Boolean durable, Boolean exclusive, Boolean autoDelete, Boolean nowait, IDictionary arguments) <0x40d38f30 + 0x00113> in <filename unknow$
at UsagiMQ.Program.GetChannel (Int32 index) <0x40cf98c0 + 0x0045c> in <filename unknown>:0
at UsagiMQ.Program.Enqueue (System.String message) <0x40d3a030 + 0x00013> in <filename unknown>:0
at UsagiMQ.Program.Main (System.String[] args) <0x40cf4d50 + 0x009a7> in <filename unknown>:0
# nano tamesi35a2_cs.err.log
(tamesi35a2_cs.cs?) GetChannel index = [1]
name_queues[index] = [1116]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [False]
nowait は仮に false 固定
arguments は仮に null 固定
Unhandled Exception:
RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=406, text="PRECONDITION_FAILED - inequivalent arg 'durable' for queue '1116' in vhost '/': received 'true' but current is 'f$
at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply () <0x41f435b0 + 0x00107> in <filename unknown>:0
at RabbitMQ.Client.Impl.ModelBase.ModelRpc (RabbitMQ.Client.Impl.MethodBase method, RabbitMQ.Client.Impl.ContentHeaderBase header, System.Byte[] body) <0x41f413f0 + 0x00101> in <filename unknown>:0
at RabbitMQ.Client.Framing.Impl.v0_8.Model.QueueDeclare (System.String queue, Boolean passive, Boolean durable, Boolean exclusive, Boolean autoDelete, Boolean nowait, IDictionary arguments) <0x41f45790 + 0x00113> in <filename unknown>:0
at Program.GetChannel (Int32 index) <0x41f05890 + 0x00436> in <filename unknown>:0
at Program.StartConsume () <0x41f057d0 + 0x0000f> in <filename unknown>:0
at Program.Main (System.String[] args) <0x41f03270 + 0x0037b> in <filename unknown>:0
[ERROR] FATAL UNHANDLED EXCEPTION: RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=406, text="PRECONDITION_FAILED - inequivalent arg 'durable' for queue '1116' in vhost '/'$
at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply () <0x41f435b0 + 0x00107> in <filename unknown>:0
at RabbitMQ.Client.Impl.ModelBase.ModelRpc (RabbitMQ.Client.Impl.MethodBase method, RabbitMQ.Client.Impl.ContentHeaderBase header, System.Byte[] body) <0x41f413f0 + 0x00101> in <filename unknown>:0
at RabbitMQ.Client.Framing.Impl.v0_8.Model.QueueDeclare (System.String queue, Boolean passive, Boolean durable, Boolean exclusive, Boolean autoDelete, Boolean nowait, IDictionary arguments) <0x41f45790 + 0x00113> in <filename unknown>:0
at Program.GetChannel (Int32 index) <0x41f05890 + 0x00436> in <filename unknown>:0
at Program.StartConsume () <0x41f057d0 + 0x0000f> in <filename unknown>:0
at Program.Main (System.String[] args) <0x41f03270 + 0x0037b> in <filename unknown>:0
# nano tamesi35a2_cs.out.log
(0) name=[1117] lifeSpan=[Durable]
(1) name=[1116] lifeSpan=[Durable]
うーむ、
RabbitMQ.Client.Framing.Impl.v0_8.Model.QueueDeclare (System.String queue, Boolean passive, Boolean durable, Boolean exclusive, Boolean autoDelete, Boolean nowait, IDictionary arguments)
この引数の順序はあってるんだろうか?
順序はあってるし、どうも UBUNTU だと false と言ってくる。 UBUNTU のときだけ全部 false にしてみるか?
UBUNTUのときだけ引数をfalse にするとどうか?
root@tk2-217-18401:/home/★user/shogi/csharp_service# ./tamesi35a2_cs.exe --msgqueue 1117 durable 1116 durable > ./tamesi35a2_cs.out.log 2> ./tamesi35a2_cs.err.log < /dev/null &
[3] 31371
root@tk2-217-18401:/home/★user/shogi/csharp_service# ./tamesi34_cs.exe 2> ./tamesi34_cs.err.log
削除したいキューがあれば名前を、無ければ空文字列を入れろだぜ☆(^~^)
キュー名を入力 : キューを削除します
空文字列で[Enter] : 次のステップへ進む
Name or empty ? >
エンキュー先のメッセージ・キューの名前を入れろだぜ☆(^~^)
Queue name? > 1116
エンキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(1) durable : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが1人も接続していなかったら消す
(4) passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > 1
デキュー先のメッセージ・キューの名前を入れろだぜ☆(^~^)
Queue name? > 1117
デキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(1) durable : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが1人も接続していなかったら消す
(4) passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > 1
tamesi34_cs.cs Dump
name_queues [ENQUEUE_INDEX] =[1116]
lifeSpan_queues [ENQUEUE_INDEX] =[Durable]
durable_lifeSpans [ENQUEUE_INDEX] =[True]
autodelete_lifeSpans[ENQUEUE_INDEX] =[False]
passive_lifeSpans [ENQUEUE_INDEX] =[False]
exclusive_lifeSpans [ENQUEUE_INDEX] =[False]
----
name_queues [DEQUEUE_INDEX] =[1117]
lifeSpan_queues [DEQUEUE_INDEX] =[Durable]
durable_lifeSpans [DEQUEUE_INDEX] =[True]
autodelete_lifeSpans[DEQUEUE_INDEX] =[False]
passive_lifeSpans [DEQUEUE_INDEX] =[False]
exclusive_lifeSpans [DEQUEUE_INDEX] =[False]
----
name_queues [DELETEQUEUE_INDEX]=[]
lifeSpan_queues [DELETEQUEUE_INDEX]=[0]
durable_lifeSpans [DELETEQUEUE_INDEX]=[False]
autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
passive_lifeSpans [DELETEQUEUE_INDEX]=[False]
exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
----
(tamesi34_cs.cs?) GetChannel index = [1]
name_queues[index] = [1117]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [False]
nowait は仮に false 固定
arguments は仮に null 固定
終了するときは[Ctrl]+[C]キーを押せだぜ☆(^~^)
エンキューするときはメッセージを打ち込んで[Enter]キーを押せだぜ☆(^◇^)
Enqueue? > usi
tamesi34_cs.cs Dump
name_queues [ENQUEUE_INDEX] =[1116]
lifeSpan_queues [ENQUEUE_INDEX] =[Durable]
durable_lifeSpans [ENQUEUE_INDEX] =[True]
autodelete_lifeSpans[ENQUEUE_INDEX] =[False]
passive_lifeSpans [ENQUEUE_INDEX] =[False]
exclusive_lifeSpans [ENQUEUE_INDEX] =[False]
----
name_queues [DEQUEUE_INDEX] =[1117]
lifeSpan_queues [DEQUEUE_INDEX] =[Durable]
durable_lifeSpans [DEQUEUE_INDEX] =[True]
autodelete_lifeSpans[DEQUEUE_INDEX] =[False]
passive_lifeSpans [DEQUEUE_INDEX] =[False]
exclusive_lifeSpans [DEQUEUE_INDEX] =[False]
----
name_queues [DELETEQUEUE_INDEX]=[]
lifeSpan_queues [DELETEQUEUE_INDEX]=[0]
durable_lifeSpans [DELETEQUEUE_INDEX]=[False]
autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
passive_lifeSpans [DELETEQUEUE_INDEX]=[False]
exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
----
(tamesi34_cs.cs?) GetChannel index = [0]
name_queues[index] = [1116]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [False]
nowait は仮に false 固定
arguments は仮に null 固定
[3] Exit 1 ./tamesi35a2_cs.exe --msgqueue 1117 durable 1116 durable > ./tamesi35a2_cs.out.log 2> ./tamesi35a2_cs.err.log < /dev/null
落ちているようだ。
(tamesi35a2_cs.cs?) GetChannel index = [1]
name_queues[index] = [1116]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [False]
nowait は仮に false 固定
arguments は仮に null 固定
Unhandled Exception:
RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=406, text="PRECONDITION_FAILED - inequivalent arg 'durable' for queue '1116' in vhost '/': re$
at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply () <0x403416a0 + 0x00107> in <filename unknown>:0
at RabbitMQ.Client.Impl.ModelBase.ModelRpc (RabbitMQ.Client.Impl.MethodBase method, RabbitMQ.Client.Impl.ContentHeaderBase header, System.Byte[] body) <0x4033f520 + 0x000fd> in <filename unknown>:0
at RabbitMQ.Client.Framing.Impl.v0_8.Model.QueueDeclare (System.String queue, Boolean passive, Boolean durable, Boolean exclusive, Boolean autoDelete, Boolean nowait, IDictionary arguments) <0x40343880 + 0x00113> in <filename un$
at Program.GetChannel (Int32 index) <0x40303890 + 0x00436> in <filename unknown>:0
at Program.StartConsume () <0x403037d0 + 0x0000f> in <filename unknown>:0
at Program.Main (System.String[] args) <0x40301270 + 0x0037b> in <filename unknown>:0
[ERROR] FATAL UNHANDLED EXCEPTION: RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=406, text="PRECONDITION_FAILED - inequivalent arg 'durable$
at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply () <0x403416a0 + 0x00107> in <filename unknown>:0
at RabbitMQ.Client.Impl.ModelBase.ModelRpc (RabbitMQ.Client.Impl.MethodBase method, RabbitMQ.Client.Impl.ContentHeaderBase header, System.Byte[] body) <0x4033f520 + 0x000fd> in <filename unknown>:0
at RabbitMQ.Client.Framing.Impl.v0_8.Model.QueueDeclare (System.String queue, Boolean passive, Boolean durable, Boolean exclusive, Boolean autoDelete, Boolean nowait, IDictionary arguments) <0x40343880 + 0x00113> in <filename un$
at Program.GetChannel (Int32 index) <0x40303890 + 0x00436> in <filename unknown>:0
at Program.StartConsume () <0x403037d0 + 0x0000f> in <filename unknown>:0
at Program.Main (System.String[] args) <0x40301270 + 0x0037b> in <filename unknown>:0
RabbitMQ.Client.Exceptions.OperationInterruptedException
というのは、どういうエラーなのか?
(public class OperationInterruptedException)「www.rabbitmq.com」
https://www.rabbitmq.com/releases/rabbitmq-dotnet-client/v2.8.6/rabbitmq-dotnet-client-2.8.6-client-htmldoc/html/type-RabbitMQ.Client.Exceptions.OperationInterruptedException.html
Ubuntu16.04 だと、TCP接続がなぜ切れるのか?
Console.WriteLine( "("+i+") name=["+ name_queues[i] + "] lifeSpan=["+ lifeSpan_queues[i] + "]");
こういうテスト用の標準出力を全部 コメントアウトしてみよう。
終了するときは[Ctrl]+[C]キーを押せだぜ☆(^~^)
エンキューするときはメッセージを打ち込んで[Enter]キーを押せだぜ☆(^◇^)
Enqueue? > usi
tamesi34_cs.cs Dump
name_queues [ENQUEUE_INDEX] =[1116]
lifeSpan_queues [ENQUEUE_INDEX] =[Durable]
durable_lifeSpans [ENQUEUE_INDEX] =[True]
autodelete_lifeSpans[ENQUEUE_INDEX] =[False]
passive_lifeSpans [ENQUEUE_INDEX] =[False]
exclusive_lifeSpans [ENQUEUE_INDEX] =[False]
----
name_queues [DEQUEUE_INDEX] =[1117]
lifeSpan_queues [DEQUEUE_INDEX] =[Durable]
durable_lifeSpans [DEQUEUE_INDEX] =[True]
autodelete_lifeSpans[DEQUEUE_INDEX] =[False]
passive_lifeSpans [DEQUEUE_INDEX] =[False]
exclusive_lifeSpans [DEQUEUE_INDEX] =[False]
----
name_queues [DELETEQUEUE_INDEX]=[]
lifeSpan_queues [DELETEQUEUE_INDEX]=[0]
durable_lifeSpans [DELETEQUEUE_INDEX]=[False]
autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
passive_lifeSpans [DELETEQUEUE_INDEX]=[False]
exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
----
(tamesi34_cs.cs?) GetChannel index = [0]
name_queues[index] = [1116]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [False]
nowait は仮に false 固定
arguments は仮に null 固定
[3] Exit 1 ./tamesi35a2_cs.exe --msgqueue 1117 durable 1116 durable > ./tamesi35a2_cs.out.log 2> ./tamesi35a2_cs.err.log < /dev/null
それでもダメ。
received 'true' but current is 'false'", classId=50, methodId=10, cause=
received 'true' but current is 'false'", classId=50, methodId=10, cause=
うーむ。
ググろう
「PRECONDITION_FAILED - inequivalent arg 'durable' for queue #370」(MassTransit/MassTransit)
https://github.com/MassTransit/MassTransit/issues/370
「Issue in establishing connection with Rabbit MQ」(stack overflow)
http://stackoverflow.com/questions/31762563/issue-in-establishing-connection-with-rabbit-mq
「Correct config using rabbitmq as celery backend」(stack overflow)
http://stackoverflow.com/questions/27623940/correct-config-using-rabbitmq-as-celery-backend
複数指定したい
--msgqueue 1117 durable 1116 durable
これを、
--enqueue durable autodelete --dequeue durable autodelete
みたいに、複数指定できるようにしたい。
こんな感じだろうか。
//--------------------------------------------------------------------------------
// tamesi35a2_cs.cs
//
// メッセージの末尾に daze を付けます。
// 標準入出力は、キーボード、画面には接続しないようにします。
// キューの名前はコマンドライン引数で指定してください。
// デキューは割込みを受け付けます。
//--------------------------------------------------------------------------------
// OS : Windows 10
// IDE : Visual Studio 2015
// Install : NuGet : Install-Package RabbitMQ.Client -Version 4.1.1
// Execute : Command : ./tamesi35a2_cs.exe --enqueue 1117 durable --dequeue 1116 durable
//
// OS : Ubuntu 16.04
// Compile : Command : mcs /r:RabbitMQ.Client.dll -define:UBUNTU tamesi35a2_cs.cs
// Execute : Command : // バックグラウンドで実行する
// : nohup ./tamesi35a2_cs.exe --enqueue 1117 durable autodelete --dequeue 1116 durable autodelete > ./tamesi35a2_cs.out.log 2> ./tamesi35a2_cs.err.log < /dev/null &
// Check : : // tamesi33a1_cs.exe を使う
//--------------------------------------------------------------------------------
// Ubuntu の RabbitMQ はソースのバージョンが古いのか、API が異なった。
// #define UBUNTU
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Text;
using System.Threading;
/// <summary>
/// このプログラム内だけで使われる数字。AMQP-CPPでの実装とは異なる。
/// AMQP-CPPでの実装 : AMQP::durable=[1] AMQP::autodelete=[2] AMQP::passive=[8] AMQP::exclusive=[512]
/// </summary>
[Flags]
enum LifeSpanType
{
/// <summary>
/// RabbitMQが止まってもキューを残す
/// </summary>
Durable = 1,
/// <summary>
/// コンシューマーが1人も接続していなかったら消す
/// </summary>
Autodelete = 0x1 << 1,
/// <summary>
/// キューが存在するかどうかチェックするだけ。中身見ない時これ
/// </summary>
Passive = 0x1 << 2,
/// <summary>
/// この接続でだけ使える。この接続が切れたら消す
/// </summary>
Exclusive = 0x1 << 3
}
/// <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)
/// 参照 : C#でconstな配列を実現する (もっとクールにプログラミング) http://pgnote.net/?p=885
/// </summary>
class Program
{
const int ENQUEUE_INDEX = 0;
const int DEQUEUE_INDEX = 1;
const int NUM_INDEX = 2;
const string HOST_NAME = "localhost";
static string[] name_queues = new string[NUM_INDEX];
/// <summary>
/// キューの寿命(複合可能)
/// durable : RabbitMQが止まってもキューを残す
/// autodelete : コンシューマーが1人も接続していなかったら消す
/// passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
/// exclusive : この接続でだけ使える。この接続が切れたら消す
/// </summary>
static LifeSpanType[] lifeSpan_queues = new LifeSpanType[NUM_INDEX];
static LifeSpanType LifeSpanString_To_Enum(string lifeSpan)
{
switch (lifeSpan)
{
case "durable": return LifeSpanType.Durable;
case "autodelete": return LifeSpanType.Autodelete;
case "passive": return LifeSpanType.Passive;
case "exclusive": return LifeSpanType.Exclusive;
default: throw new Exception("未対応のlifeSpan [" + lifeSpan + "]");
}
}
static bool[]
durable_lifeSpans = new bool[NUM_INDEX],
autodelete_lifeSpans = new bool[NUM_INDEX],
passive_lifeSpans = new bool[NUM_INDEX],
exclusive_lifeSpans = new bool[NUM_INDEX];
static void SetLifeSpan(int index_queue, string name_queue, LifeSpanType lifeSpan)
{
// 一旦クリアー
durable_lifeSpans[index_queue] = false;
autodelete_lifeSpans[index_queue] = false;
passive_lifeSpans[index_queue] = false;
exclusive_lifeSpans[index_queue] = false;
// durable
if (((int)lifeSpan & (int)LifeSpanType.Durable) == (int)LifeSpanType.Durable) { durable_lifeSpans[index_queue] = true; }
// autodelete
if (((int)lifeSpan & (int)LifeSpanType.Autodelete) == (int)LifeSpanType.Autodelete) { autodelete_lifeSpans[index_queue] = true; }
// passive
if (((int)lifeSpan & (int)LifeSpanType.Passive) == (int)LifeSpanType.Passive) { passive_lifeSpans[index_queue] = true; }
// exclusive
if (((int)lifeSpan & (int)LifeSpanType.Exclusive) == (int)LifeSpanType.Exclusive) { exclusive_lifeSpans[index_queue] = true; }
}
// 回転式バッファー
static RotationBuffer rollingBuffer = new RotationBuffer();
static ConnectionFactory GetFactory()
{
if (null == m_factory_)
{
m_factory_ = new ConnectionFactory() { HostName = HOST_NAME };
}
return m_factory_;
}
static ConnectionFactory m_factory_;
static IConnection GetConnection()
{
if (null == m_connection_)
{
m_connection_ = GetFactory().CreateConnection();
}
return m_connection_;
}
static IConnection m_connection_;
static bool IsConnected()
{
if (null != m_connection_)
{
return m_connection_.IsOpen;
}
return false;
}
static IModel GetChannel(int index)
{
if (null == m_channels_[index])
{
m_channels_[index] = GetConnection().CreateModel();
// 引数が7つの QueueDeclare でエラーを吐くことがあるので、情報を出力しておく。
Console.Error.WriteLine("(tamesi35a2_cs.cs?) GetChannel index = [" + index + "]");
Console.Error.WriteLine(" name_queues[index] = [" + name_queues[index] + "]");
Console.Error.WriteLine(" passive_lifeSpans[index] = [" + passive_lifeSpans[index] + "]");
Console.Error.WriteLine(" durable_lifeSpans[index] = [" + durable_lifeSpans[index] + "]");
Console.Error.WriteLine(" exclusive_lifeSpans[index] = [" + exclusive_lifeSpans[index] + "]");
Console.Error.WriteLine(" autodelete_lifeSpans[index] = [" + autodelete_lifeSpans[index] + "]");
Console.Error.WriteLine(" nowait は仮に false 固定");
Console.Error.WriteLine(" arguments は仮に null 固定");
#if UBUNTU
// Ubuntuでは何故か Spring.Messaging.Amqp.Rabbit の引数 7 つのやつになっている。
// m_channels_[index].QueueDeclare(name_queues[index], false, false, false, false, false, null);
// そして false になっているようだ。
m_channels_[index].QueueDeclare(name_queues[index], passive_lifeSpans[index], durable_lifeSpans[index], exclusive_lifeSpans[index], autodelete_lifeSpans[index], false, null);
//m_channels_[index].QueueDeclare(name_queues[index], false, false, false, false, false, null);
#else
//m_channels_[index].QueueDeclare(name_queues[index], false, false, false, null);
m_channels_[index].QueueDeclare(name_queues[index], durable_lifeSpans[index], exclusive_lifeSpans[index], autodelete_lifeSpans[index], null);
#endif
}
return m_channels_[index];
}
static IModel[] m_channels_ = new IModel[2];
static EventingBasicConsumer GetConsumer(int index)
{
if (null == m_consumers_[index])
{
#if UBUNTU
// Ubuntuでは何故か v1.4.0 の引数が 0 個のやつになっている。調べたが引数が1個~6個のものは無かった。
m_consumers_[index] = new EventingBasicConsumer();
#else
m_consumers_[index] = new EventingBasicConsumer(GetChannel(index));
#endif
}
return m_consumers_[index];
}
static EventingBasicConsumer[] m_consumers_ = new EventingBasicConsumer[2];
/// <summary>
/// 受信できたときに割り込んでくる処理
/// </summary>
#if UBUNTU
public static BasicDeliverEventHandler GetDequeueHandler()
#else
static EventHandler<BasicDeliverEventArgs> GetDequeueHandler()
#endif
{
if (null == m_dequeueHandler_)
{
#if UBUNTU
m_dequeueHandler_ = new BasicDeliverEventHandler((model, ea) =>
#else
m_dequeueHandler_ = new EventHandler<BasicDeliverEventArgs>((model, ea) =>
#endif
{
byte[] body = ea.Body;
string message = Encoding.UTF8.GetString(body);
// 回転式バッファーに入れる
rollingBuffer.PutMessage(message);
});
}
return m_dequeueHandler_;
}
#if UBUNTU
static BasicDeliverEventHandler m_dequeueHandler_;
#else
static EventHandler<BasicDeliverEventArgs> m_dequeueHandler_;
#endif
/// <summary>
/// 対応するオープンは無いけれど、開けたら閉める、を完璧に対応する必要がある。
/// </summary>
static void CloseChannel(int index)
{
if (null != m_channels_[index])
{
m_channels_[index].Close();
m_channels_[index] = null;
}
}
static void Enqueue(string message)
{
// 末尾に daze を付ける。
message += "daze";
IModel channel = GetChannel(ENQUEUE_INDEX);
byte[] body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish("", name_queues[ENQUEUE_INDEX], null, body);
// 対応するオープンは無いが、ちゃんと閉じないと、レシーブしてくれない。
CloseChannel(ENQUEUE_INDEX);
}
static void StartConsume()
{
IModel channel = GetChannel(DEQUEUE_INDEX);
EventingBasicConsumer consumer = GetConsumer(DEQUEUE_INDEX);
// 受信できたときに割り込んでくる処理
consumer.Received += GetDequeueHandler();
#if UBUNTU
// Ubuntuでは何故か引数が 5 個のやつになっている。
channel.BasicConsume( name_queues[DEQUEUE_INDEX], true, "", null, consumer);
#else
channel.BasicConsume( name_queues[DEQUEUE_INDEX], true, consumer);
#endif
// 終了はさせない
// consumer.Received -= GetReceiveHandler();
// CloseChannel(DEQUEUE_INDEX);
}
static void StartProduce()
{
// 無限ループ
while (IsConnected())
{
string message = rollingBuffer.GetMessage();
if (null != message)
{
// エンキューする
Enqueue(message);
}
Thread.Sleep(20);
}
}
static void Main(string[] args)
{
if (args.Length<1)
{
goto gt_Error1;
}
// 引数の解析
{
// 与件
// 「--enqueue 1117 durable autodelete --dequeue 1116 durable autodelete」
// 寿命は可変個数設定可能「durable」「autodelete」「passive」「exclusive」
// 受け皿
// 0:enqueue 1:dequeue
// 記憶
int m0 = 0; // 0:ニュートラル 1:enqueue 2:dequeue
int m1 = 0; // 0:寿命カーソル
// 解析器
foreach (string a in args)
{
if (a.StartsWith("--"))
{
switch (a)
{
case "--enqueue": m0=1; m1=0; break;
case "--dequeue": m0=2; m1=0; break;
default: goto gt_Error1;
}
}
else if (0 == m1) { name_queues[m0 - 1] = a; m1++; }
else { lifeSpan_queues[m0 - 1] |= LifeSpanString_To_Enum(a); m1++; }
}
// 結果
for (int i = 0; i < 2; i++)
{
Console.WriteLine( "("+i+") name=["+ name_queues[i] + "] lifeSpan=["+ lifeSpan_queues[i] + "]");
SetLifeSpan(i, name_queues[i], lifeSpan_queues[i]);
}
}
// 常時監視をスタート
StartConsume();
StartProduce();
// このプログラムは、自分では接続を切らない。
return;
gt_Error1:
throw new Exception(@"コマンドライン引数に「--msgqueue キュー名 寿命 キュー名 寿命」を指定しろだぜ☆(^~^)
エンキュー先、デキュー先の順番な☆(^▽^)
寿命は durable, autodelete, passive, exclusive のいずれかで、
複合指定にはまだ対応していないぜ☆(>_<)");
}
}
/// <summary>
/// 回転式バッファー。
/// これはメイン・スレッドに置く。
/// デキューのスレッドでエンキューすることはできない。
/// デキュー処理は、回転式バッファーを仲介にしてエンキュー処理にメッセージを渡す。
/// </summary>
public class RotationBuffer
{
public const int bufferSize = 100;
public string[] buffer = new string[bufferSize];
public int[] bufferCursors = new int[] { 0, 0 };
public const int PUT_INDEX = 0;
public const int GET_INDEX = 1;
public void PutMessage(string message)
{
buffer[bufferCursors[PUT_INDEX]] = message;
bufferCursors[PUT_INDEX]++;
if (!(bufferCursors[PUT_INDEX] < bufferSize))
{
bufferCursors[PUT_INDEX] = 0;
}
}
public string GetMessage()
{
if (null != buffer[bufferCursors[GET_INDEX]])
{
string message = buffer[bufferCursors[GET_INDEX]];
buffer[bufferCursors[GET_INDEX]] = null;
bufferCursors[GET_INDEX]++;
if (!(bufferCursors[GET_INDEX] < bufferSize))
{
bufferCursors[GET_INDEX] = 0;
}
return message;
}
return null;
}
}
root@tk2-217-18401:/home/★user/shogi/csharp_service# rm tamesi35a2_cs.cs
root@tk2-217-18401:/home/★user/shogi/csharp_service# nano tamesi35a2_cs.cs
root@tk2-217-18401:/home/★user/shogi/csharp_service# mcs /r:RabbitMQ.Client.dll -define:UBUNTU tamesi35a2_cs.cs
root@tk2-217-18401:/home/★user/shogi/csharp_service# ./tamesi35a2_cs.exe --enqueue 1117 durable autodelete --dequeue 1116 durable autodelete > ./tamesi35a2_cs.out.log 2> ./tamesi35a2_cs.err.log < /dev/null &
[4] 470
root@tk2-217-18401:/home/★user/shogi/csharp_service# ./tamesi34_cs.exe 2> ./tamesi34_cs.err.log
削除したいキューがあれば名前を、無ければ空文字列を入れろだぜ☆(^~^)
キュー名を入力 : キューを削除します
空文字列で[Enter] : 次のステップへ進む
Name or empty ? >
エンキュー先のメッセージ・キューの名前を入れろだぜ☆(^~^)
Queue name? > 1116
エンキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(1) durable : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが1人も接続していなかったら消す
(4) passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > 3
デキュー先のメッセージ・キューの名前を入れろだぜ☆(^~^)
Queue name? > 1117
デキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(1) durable : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが1人も接続していなかったら消す
(4) passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > 3
tamesi34_cs.cs Dump
name_queues [ENQUEUE_INDEX] =[1116]
lifeSpan_queues [ENQUEUE_INDEX] =[Durable, Autodelete]
durable_lifeSpans [ENQUEUE_INDEX] =[True]
autodelete_lifeSpans[ENQUEUE_INDEX] =[True]
passive_lifeSpans [ENQUEUE_INDEX] =[False]
exclusive_lifeSpans [ENQUEUE_INDEX] =[False]
----
name_queues [DEQUEUE_INDEX] =[1117]
lifeSpan_queues [DEQUEUE_INDEX] =[Durable, Autodelete]
durable_lifeSpans [DEQUEUE_INDEX] =[True]
autodelete_lifeSpans[DEQUEUE_INDEX] =[True]
passive_lifeSpans [DEQUEUE_INDEX] =[False]
exclusive_lifeSpans [DEQUEUE_INDEX] =[False]
----
name_queues [DELETEQUEUE_INDEX]=[]
lifeSpan_queues [DELETEQUEUE_INDEX]=[0]
durable_lifeSpans [DELETEQUEUE_INDEX]=[False]
autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
passive_lifeSpans [DELETEQUEUE_INDEX]=[False]
exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
----
(tamesi34_cs.cs?) GetChannel index = [1]
name_queues[index] = [1117]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [True]
nowait は仮に false 固定
arguments は仮に null 固定
[4] Exit 1 ./tamesi35a2_cs.exe --enqueue 1117 durable autodelete --dequeue 1116 durable autodelete > ./tamesi35a2_cs.out.log 2> ./tamesi35a2_cs.err.log < /dev/null
(tamesi35a2_cs.cs?) GetChannel index = [1]
name_queues[index] = [1116]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [True]
nowait は仮に false 固定
arguments は仮に null 固定
Unhandled Exception:
RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=406, text="PRECONDITION_FAILED - inequivalent arg 'durable' for queue '1116' in vhost '/': recei$
at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply () <0x40044590 + 0x00103> in <filename unknown>:0
at RabbitMQ.Client.Impl.ModelBase.ModelRpc (RabbitMQ.Client.Impl.MethodBase method, RabbitMQ.Client.Impl.ContentHeaderBase header, System.Byte[] body) <0x40042520 + 0x000f9> in <filename unknown>:0
at RabbitMQ.Client.Framing.Impl.v0_8.Model.QueueDeclare (System.String queue, Boolean passive, Boolean durable, Boolean exclusive, Boolean autoDelete, Boolean nowait, IDictionary arguments) <0x400467d0 + 0x00113> in <filename unkno$
at Program.GetChannel (Int32 index) <0x400078d0 + 0x00436> in <filename unknown>:0
at Program.StartConsume () <0x40007810 + 0x0000f> in <filename unknown>:0
at Program.Main (System.String[] args) <0x40004270 + 0x003cb> in <filename unknown>:0
[ERROR] FATAL UNHANDLED EXCEPTION: RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=406, text="PRECONDITION_FAILED - inequivalent arg 'durable' f$
at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply () <0x40044590 + 0x00103> in <filename unknown>:0
at RabbitMQ.Client.Impl.ModelBase.ModelRpc (RabbitMQ.Client.Impl.MethodBase method, RabbitMQ.Client.Impl.ContentHeaderBase header, System.Byte[] body) <0x40042520 + 0x000f9> in <filename unknown>:0
at RabbitMQ.Client.Framing.Impl.v0_8.Model.QueueDeclare (System.String queue, Boolean passive, Boolean durable, Boolean exclusive, Boolean autoDelete, Boolean nowait, IDictionary arguments) <0x400467d0 + 0x00113> in <filename unkno$
at Program.GetChannel (Int32 index) <0x400078d0 + 0x00436> in <filename unknown>:0
at Program.StartConsume () <0x40007810 + 0x0000f> in <filename unknown>:0
at Program.Main (System.String[] args) <0x40004270 + 0x003cb> in <filename unknown>:0
うーむ。
root@tk2-217-18401:/home/csg10/shogi/csharp_service# ./tamesi34_cs.exe 2> ./tamesi34_cs.err.log
削除したいキューがあれば名前を、無ければ空文字列を入れろだぜ☆(^~^)
キュー名を入力 : キューを削除します
空文字列で[Enter] : 次のステップへ進む
Name or empty ? >
エンキュー先のメッセージ・キューの名前を入れろだぜ☆(^~^)
Queue name? > 1116
エンキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(1) durable : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが1人も接続していなかったら消す
(4) passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > 3
デキュー先のメッセージ・キューの名前を入れろだぜ☆(^~^)
Queue name? > 1117
デキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(1) durable : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが1人も接続していなかったら消す
(4) passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > 3
tamesi34_cs.cs Dump
name_queues [ENQUEUE_INDEX] =[1116]
lifeSpan_queues [ENQUEUE_INDEX] =[Durable, Autodelete]
durable_lifeSpans [ENQUEUE_INDEX] =[True]
autodelete_lifeSpans[ENQUEUE_INDEX] =[True]
passive_lifeSpans [ENQUEUE_INDEX] =[False]
exclusive_lifeSpans [ENQUEUE_INDEX] =[False]
----
name_queues [DEQUEUE_INDEX] =[1117]
lifeSpan_queues [DEQUEUE_INDEX] =[Durable, Autodelete]
durable_lifeSpans [DEQUEUE_INDEX] =[True]
autodelete_lifeSpans[DEQUEUE_INDEX] =[True]
passive_lifeSpans [DEQUEUE_INDEX] =[False]
exclusive_lifeSpans [DEQUEUE_INDEX] =[False]
----
name_queues [DELETEQUEUE_INDEX]=[]
lifeSpan_queues [DELETEQUEUE_INDEX]=[0]
durable_lifeSpans [DELETEQUEUE_INDEX]=[False]
autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
passive_lifeSpans [DELETEQUEUE_INDEX]=[False]
exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
----
(tamesi34_cs.cs?) GetChannel index = [1]
name_queues[index] = [1117]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [True]
nowait は仮に false 固定
arguments は仮に null 固定
[3] Exit 1 ./tamesi35a2_cs.exe --enqueue 1117 durable autodelete --dequeue 1116 durable autodelete > ./tamesi35a2_cs.out.log 2> ./tamesi35a2_cs.err.log < /dev/null
これでもダメか。
ググろう
PRECONDITION_FAILED - inequivalent arg 'durable
キューを削除しよう
root@tk2-217-18401:/home/csg10/shogi/csharp_service# rabbitmqctl list_queues
Listing queues ...
1117 0
1118 0
myqueue 0
1115 0
1114 0
1119 0
root@tk2-217-18401:/home/csg10/shogi/csharp_service# ./tamesi34_cs.exe 2> ./tamesi34_cs.err.log
削除したいキューがあれば名前を、無ければ空文字列を入れろだぜ☆(^~^)
キュー名を入力 : キューを削除します
空文字列で[Enter] : 次のステップへ進む
Name or empty ? > myqueue
削除するメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(1) durable : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが1人も接続していなかったら消す
(4) passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > 1
tamesi34_cs.cs Dump
name_queues [ENQUEUE_INDEX] =[]
lifeSpan_queues [ENQUEUE_INDEX] =[0]
durable_lifeSpans [ENQUEUE_INDEX] =[False]
autodelete_lifeSpans[ENQUEUE_INDEX] =[False]
passive_lifeSpans [ENQUEUE_INDEX] =[False]
exclusive_lifeSpans [ENQUEUE_INDEX] =[False]
----
name_queues [DEQUEUE_INDEX] =[]
lifeSpan_queues [DEQUEUE_INDEX] =[0]
durable_lifeSpans [DEQUEUE_INDEX] =[False]
autodelete_lifeSpans[DEQUEUE_INDEX] =[False]
passive_lifeSpans [DEQUEUE_INDEX] =[False]
exclusive_lifeSpans [DEQUEUE_INDEX] =[False]
----
name_queues [DELETEQUEUE_INDEX]=[myqueue]
lifeSpan_queues [DELETEQUEUE_INDEX]=[Durable]
durable_lifeSpans [DELETEQUEUE_INDEX]=[True]
autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
passive_lifeSpans [DELETEQUEUE_INDEX]=[False]
exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
----
(tamesi34_cs.cs?) GetChannel index = [2]
name_queues[index] = [myqueue]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [False]
nowait は仮に false 固定
arguments は仮に null 固定
[myqueue]キューを削除したはずだぜ☆(^~^) result=[4294967295]
削除したいキューがあれば名前を、無ければ空文字列を入れろだぜ☆(^~^)
キュー名を入力 : キューを削除します
空文字列で[Enter] : 次のステップへ進む
# rabbitmqctl list_queues
Listing queues ...
1117 0
1118 0
1115 0
1114 0
1119 0
# ./tamesi34_cs.exe 2> ./tamesi34_cs.err.log
削除したいキューがあれば名前を、無ければ空文字列を入れろだぜ☆(^~^)
キュー名を入力 : キューを削除します
空文字列で[Enter] : 次のステップへ進む
Name or empty ? > 1114
削除するメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(1) durable : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが1人も接続していなかったら消す
(4) passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > 1
tamesi34_cs.cs Dump
name_queues [ENQUEUE_INDEX] =[]
lifeSpan_queues [ENQUEUE_INDEX] =[0]
durable_lifeSpans [ENQUEUE_INDEX] =[False]
autodelete_lifeSpans[ENQUEUE_INDEX] =[False]
passive_lifeSpans [ENQUEUE_INDEX] =[False]
exclusive_lifeSpans [ENQUEUE_INDEX] =[False]
----
name_queues [DEQUEUE_INDEX] =[]
lifeSpan_queues [DEQUEUE_INDEX] =[0]
durable_lifeSpans [DEQUEUE_INDEX] =[False]
autodelete_lifeSpans[DEQUEUE_INDEX] =[False]
passive_lifeSpans [DEQUEUE_INDEX] =[False]
exclusive_lifeSpans [DEQUEUE_INDEX] =[False]
----
name_queues [DELETEQUEUE_INDEX]=[1114]
lifeSpan_queues [DELETEQUEUE_INDEX]=[Durable]
durable_lifeSpans [DELETEQUEUE_INDEX]=[True]
autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
passive_lifeSpans [DELETEQUEUE_INDEX]=[False]
exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
----
(tamesi34_cs.cs?) GetChannel index = [2]
name_queues[index] = [1114]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [False]
nowait は仮に false 固定
arguments は仮に null 固定
[1114]キューを削除したはずだぜ☆(^~^) result=[4294967295]
削除したいキューがあれば名前を、無ければ空文字列を入れろだぜ☆(^~^)
キュー名を入力 : キューを削除します
空文字列で[Enter] : 次のステップへ進む
# rabbitmqctl list_queues
Listing queues ...
1117 0
1118 0
1115 0
1119 0
# ./tamesi34_cs.exe 2> ./tamesi34_cs.err.log
削除したいキューがあれば名前を、無ければ空文字列を入れろだぜ☆(^~^)
キュー名を入力 : キューを削除します
空文字列で[Enter] : 次のステップへ進む
Name or empty ? > 1115
削除するメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(1) durable : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが1人も接続していなかったら消す
(4) passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > 1
tamesi34_cs.cs Dump
name_queues [ENQUEUE_INDEX] =[]
lifeSpan_queues [ENQUEUE_INDEX] =[0]
durable_lifeSpans [ENQUEUE_INDEX] =[False]
autodelete_lifeSpans[ENQUEUE_INDEX] =[False]
passive_lifeSpans [ENQUEUE_INDEX] =[False]
exclusive_lifeSpans [ENQUEUE_INDEX] =[False]
----
name_queues [DEQUEUE_INDEX] =[]
lifeSpan_queues [DEQUEUE_INDEX] =[0]
durable_lifeSpans [DEQUEUE_INDEX] =[False]
autodelete_lifeSpans[DEQUEUE_INDEX] =[False]
passive_lifeSpans [DEQUEUE_INDEX] =[False]
exclusive_lifeSpans [DEQUEUE_INDEX] =[False]
----
name_queues [DELETEQUEUE_INDEX]=[1115]
lifeSpan_queues [DELETEQUEUE_INDEX]=[Durable]
durable_lifeSpans [DELETEQUEUE_INDEX]=[True]
autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
passive_lifeSpans [DELETEQUEUE_INDEX]=[False]
exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
----
(tamesi34_cs.cs?) GetChannel index = [2]
name_queues[index] = [1115]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [False]
nowait は仮に false 固定
arguments は仮に null 固定
[1115]キューを削除したはずだぜ☆(^~^) result=[4294967295]
削除したいキューがあれば名前を、無ければ空文字列を入れろだぜ☆(^~^)
キュー名を入力 : キューを削除します
空文字列で[Enter] : 次のステップへ進む
# rabbitmqctl list_queues
Listing queues ...
1117 0
1118 0
1119 0
なんかキューは durable だけ指定すれば全部消せた。
キューを全部消して、durable+autodelete で行けた?
# ./tamesi35a2_cs.exe --enqueue 1113 durable autodelete --dequeue 1112 durable autodelete > ./tamesi35a2_cs.out.log 2> ./tamesi35a2_cs.err.log < /dev/null &
[3] 2613
root@tk2-217-18401:/home/csg10/shogi/csharp_service# ./tamesi34_cs.exe
削除したいキューがあれば名前を、無ければ空文字列を入れろだぜ☆(^~^)
キュー名を入力 : キューを削除します
空文字列で[Enter] : 次のステップへ進む
Name or empty ? >
エンキュー先のメッセージ・キューの名前を入れろだぜ☆(^~^)
Queue name? > 1112
エンキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(1) durable : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが1人も接続していなかったら消す
(4) passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > 3
デキュー先のメッセージ・キューの名前を入れろだぜ☆(^~^)
Queue name? > 1113
デキュー先のメッセージ・キューの寿命を、足し算して答えろだぜ☆(^~^)
(1) durable : RabbitMQが止まってもキューを残す
(2) autodelete : コンシューマーが1人も接続していなかったら消す
(4) passive : キューが存在するかどうかチェックするだけ。中身見ない時これ
(8) exclusive : この接続でだけ使える。この接続が切れたら消す
Number ? > 3
tamesi34_cs.cs Dump
name_queues [ENQUEUE_INDEX] =[1112]
lifeSpan_queues [ENQUEUE_INDEX] =[Durable, Autodelete]
durable_lifeSpans [ENQUEUE_INDEX] =[True]
autodelete_lifeSpans[ENQUEUE_INDEX] =[True]
passive_lifeSpans [ENQUEUE_INDEX] =[False]
exclusive_lifeSpans [ENQUEUE_INDEX] =[False]
----
name_queues [DEQUEUE_INDEX] =[1113]
lifeSpan_queues [DEQUEUE_INDEX] =[Durable, Autodelete]
durable_lifeSpans [DEQUEUE_INDEX] =[True]
autodelete_lifeSpans[DEQUEUE_INDEX] =[True]
passive_lifeSpans [DEQUEUE_INDEX] =[False]
exclusive_lifeSpans [DEQUEUE_INDEX] =[False]
----
name_queues [DELETEQUEUE_INDEX]=[]
lifeSpan_queues [DELETEQUEUE_INDEX]=[0]
durable_lifeSpans [DELETEQUEUE_INDEX]=[False]
autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
passive_lifeSpans [DELETEQUEUE_INDEX]=[False]
exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
----
(tamesi34_cs.cs?) GetChannel index = [1]
name_queues[index] = [1113]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [True]
nowait は仮に false 固定
arguments は仮に null 固定
終了するときは[Ctrl]+[C]キーを押せだぜ☆(^~^)
エンキューするときはメッセージを打ち込んで[Enter]キーを押せだぜ☆(^◇^)
Enqueue? > usi
tamesi34_cs.cs Dump
name_queues [ENQUEUE_INDEX] =[1112]
lifeSpan_queues [ENQUEUE_INDEX] =[Durable, Autodelete]
durable_lifeSpans [ENQUEUE_INDEX] =[True]
autodelete_lifeSpans[ENQUEUE_INDEX] =[True]
passive_lifeSpans [ENQUEUE_INDEX] =[False]
exclusive_lifeSpans [ENQUEUE_INDEX] =[False]
----
name_queues [DEQUEUE_INDEX] =[1113]
lifeSpan_queues [DEQUEUE_INDEX] =[Durable, Autodelete]
durable_lifeSpans [DEQUEUE_INDEX] =[True]
autodelete_lifeSpans[DEQUEUE_INDEX] =[True]
passive_lifeSpans [DEQUEUE_INDEX] =[False]
exclusive_lifeSpans [DEQUEUE_INDEX] =[False]
----
name_queues [DELETEQUEUE_INDEX]=[]
lifeSpan_queues [DELETEQUEUE_INDEX]=[0]
durable_lifeSpans [DELETEQUEUE_INDEX]=[False]
autodelete_lifeSpans[DELETEQUEUE_INDEX]=[False]
passive_lifeSpans [DELETEQUEUE_INDEX]=[False]
exclusive_lifeSpans [DELETEQUEUE_INDEX]=[False]
----
(tamesi34_cs.cs?) GetChannel index = [0]
name_queues[index] = [1112]
passive_lifeSpans[index] = [False]
durable_lifeSpans[index] = [True]
exclusive_lifeSpans[index] = [False]
autodelete_lifeSpans[index] = [True]
nowait は仮に false 固定
arguments は仮に null 固定
Enqueue(^q^) usi
Enqueue? > <---- [interrupt!] Dequeue(^q^) usidaze
usidaze が返ってきている。C#では成功か?
じゃあ
-Windows10 ではデフォルトで durable
-Ubuntu ではデフォルトで durable+autodelete
か。そんなん分からんなあ。
C++でもテストしたいが
root@tk2-217-18401:/home/★user/shogi/csharp_service# jobs
[1]- Stopped nano tamesi34_cs.err.log
[2]+ Stopped nano tamesi35a2_cs.out.log
[3] Running ./tamesi35a2_cs.exe --enqueue 1113 durable autodelete --dequeue 1112 durable autodelete > ./tamesi35a2_cs.out.log 2> ./tamesi35a2_cs.err.log < /dev/null &
root@tk2-217-18401:/home/★user/shogi/csharp_service# kill %3
root@tk2-217-18401:/home/★user/shogi/csharp_service# jobs
[1]- Stopped nano tamesi34_cs.err.log
[2]+ Stopped nano tamesi35a2_cs.out.log
[3] Terminated ./tamesi35a2_cs.exe --enqueue 1113 durable autodelete --dequeue 1112 durable autodelete > ./tamesi35a2_cs.out.log 2> ./tamesi35a2_cs.err.log < /dev/null
ジョブを止めておく。
tamesi35a2.cpp をバックグラウンドで動かそう。標準入出力は捨てることが重要。
./tamesi35a2_cs.exe --enqueue 1113 durable autodelete --dequeue 1112 durable autodelete > ./tamesi35a2_cs.out.log 2> ./tamesi35a2_cs.err.log < /dev/null &
root@tk2-217-18401:~# ./tamesi35a2_cs.exe --enqueue 1113 durable autodelete --dequeue 1112 durable autodelete > ./tamesi35a2_cs.out.log 2> ./tamesi35a2_cs.err.log < /dev/null &
[1] 12555
root@tk2-217-18401:~# jobs
[1]+ Exit 127 ./tamesi35a2_cs.exe --enqueue 1113 durable autodelete --dequeue 1112 durable autodelete > ./tamesi35a2_cs.out.log 2> ./tamesi35a2_cs.err.log < /dev/null
root@tk2-217-18401:~# jobs
あれっ? これ、_cs だぜ。そして カレント・ディレクトリが違う。
root@tk2-217-18401:~# cd /home/★user/shogi/cpp_service
root@tk2-217-18401:/home/★user/shogi/cpp_service# ls
consume.cpp tamesi29a11_enqueueTcp.cpp
consume.exe tamesi29a11_enqueueTcp.exe
loop28_cpp.cpp tamesi29a7_main.cpp
loop28_cpp.exe tamesi29a7_main.exe
publish.cpp tamesi29a8_example_consume.cpp
publish.exe tamesi29a9_main.cpp
tamesi28.d tamesi29a9_main.exe
tamesi29a10_main.cpp tamesi33a2_cpp.cpp
tamesi29a10_main.exe tamesi33a2_cpp.err.log
tamesi29a11_enqueueA.cpp tamesi33a2_cpp.exe
tamesi29a11_enqueueA.exe tamesi35a2_cpp.cpp
tamesi29a11_enqueueC.cpp tamesi35a2_cpp.err.log
tamesi29a11_enqueueC.exe tamesi35a2_cpp.exe
tamesi29a11_enqueue.exe
root@tk2-217-18401:/home/★user/shogi/cpp_service# ./tamesi35a2_cpp.exe --msgqueue 1117 durable 1116 durable 2> ./tamesi35a2_cpp.err.log &
[1] 12608
root@tk2-217-18401:/home/★user/shogi/cpp_service# Welcome! AMQP::durable=[1] AMQP::autodelete=[2] AMQP::passive=[8] AMQP::exclusive=[512]
プロンプトが返ってきてしまった。困るぜ。[Entery]キーを押してみる。
# jobs
[1]+ Running ./tamesi35a2_cpp.exe --msgqueue 1117 durable 1116 durable 2> ./tamesi35a2_cpp.err.log &
動いているようだ。
#記事が長くなってきたので次へ。