これに似たものをGoogleとStackOverflowで検索しましたが、最も近いものはCコードで、状況は同じではありませんでした...
スクリプトへの cstdlib の system() 呼び出しを介して別のプログラムを開始するプログラムがあり、すべて正常に動作します。問題は、新しいコードをテストする必要があるときです。そのため、実行を停止します (Crtl+C および kill -9 pid で同じエラーが発生します)。 )、新しい実行可能ファイルをコンパイルして再度実行しようとすると、ソケットが既に使用されているというメッセージが表示されます。
私のプログラムはアクセプターを使用し、接続を待ちます (一度に 1 つずつ処理します)。ファイルの取得/送信と、別のプログラムの開始/停止を 1 つのスクリプトで実行できます。ファイルを取得/送信するだけの場合、ソケットはロックされませんが、system() 呼び出しのいずれかが実行されると、ソケットがロックされ、シャットダウンした後にプログラムを実行できなくなります。
適切に動作するため、これが実際の asio 部分と関係があるとは本当に思いませんが、これがエンドポイントの定義方法です。
ba::ip::tcp::endpoint endpoint(ba::ip::address_v4::any(), listen_port);
ba は boost::asio の略です。そしてssl:
ba::ip::tcp::acceptor acceptor_(*io,endpoint);
ba::ssl::context context_(*io, ba::ssl::context::sslv23);
context_.set_options( ba::ssl::context::default_workarounds |
ba::ssl::context::no_sslv2 |
ba::ssl::context::single_dh_use);
//Rest of context config
//Some more code
stream.reset( new ssl_stream(*io,context_) );
boost::system::error_code ec;
boost::system::error_code no_error; // default error_code = no error
while(true)
{
ec = no_error;
stream.reset( new ssl_stream(*io,context_) );
acceptor_.accept(stream->lowest_layer(), endpoint,ec);
if( !ec )
{
stream->handshake(ba::ssl::stream_base::server,ec);
if( !ec )
{
operations();
}
//rest of the code...
}//while(true) end
acceptor_.close();
if(pid == 0)
{
std::cout << "Child exiting!" << std::endl;
}
ストリームの場所:
boost::shared_ptr< boost::asio::ssl::stream<boost::asio::ip::tcp::socket> > stream;
とにかく、明確にするために、これらは2つの状況です:
最初: (OK)
# ./program
(Then, I only retrieve/send files)
# kill -9 program_pid ( or Crtl+C)
# g++ .... -o program
# ./program
(Program starts normally)
2 番目: (エラー)
#./program
(Use system() to start other program 1+ times)
# kill -9 program_pid (or Crtl+C)
# g++ .... -o program
# ./program
(Program fails to start, since socket "is already being used")
面白い事実:
- プログラムで開始した他のプログラムを (ターミナル経由で) 再起動/停止すると、ソケットが解放されます。
- fork() -> execv() 同じコマンドでも、ソケットが「ロック」されます。
- 開始されたプログラムの親 PID は 1 であり、私のプログラムの PID ではありません...
他のプログラムが何か間違ったことをしているのかもしれないと思ったので、システムコールを使用して別のプログラム(Apache、init.dのスクリプトを介して)を開始しようとしましたが、同じ結果が得られました。
ここで、「なぜこうなったのか」「どうすれば解決できるのか」に少し迷います...
system() はそれと関係があるようですが、呼び出しが返され、ソケットはそれとは関係がないため、理由はわかりません。子プロセスから ( fork() を介して) execv() を使用して同じコマンドを呼び出しても、同じエラーが発生します...
popen() はまだ試していませんが、同じ場所にたどり着くと確信しています。
編集: system() は実際には fork() の後に exec が続くことに気付いたので、それを指摘しても意味がありませんでした...
EDIT2:詳細を追加
Tanner Sansbury の回答に従って、コードを変更しましたが、結果は同じです...
操作については、操作を読み取り、関連する関数を呼び出すだけです。
それから私は自分の機能に落ちます:
//Function body:
if (this->existBinary())
{
io->notify_fork(boost::asio::io_service::fork_prepare);
pid = fork();
if( pid == 0 )
{
io->notify_fork(boost::asio::io_service::fork_child);
char binChar[80];
for(unsigned int i = 0; i < bin.size(); ++i)
{
binChar[i] = bin[i];
}
binChar[bin.size()] = '\0';
char* bin_args[] = { binChar, "start" , NULL };
execv( bin_args[0], bin_args );
}
else
{
io->notify_fork(boost::asio::io_service::fork_parent);
if( pid == -1)
{
std::cout << "Fork error" << std::endl;
}
else
{
// running in parent, wait exec to complete
// and return its exit status.
int status;
waitpid( pid, &status, 0 );
printf("Child %d exited with status %d\n", pid, status );
}
}
// returning true just for testing
return true;
}
return false;
existBinary() 関数:
bool my_class::existBinary(const std::string& filename) const
{
std::ifstream file(filename.c_str(),std::ios_base::in | std::ios_base::binary);
bool file_status = false;
if(file.is_open())
{
file_status = true;
file.close();
}
return file_status;
}
子が終了したときに cout を印刷することに注意してください。しかし、何も表示されません... :(
アクセプターをクラス メンバーに移動し、子で閉じてみます。
繰り返しますが、他のプログラムを再起動/停止すると、ソケットが解放されます...