yoshizu
2016年2月24日 10時00分
yoshizuです
いつも、お世話になっています。
atmadillo-840 atde5-i386-20140131
の環境で、armadillo側サーバーsocketが、 ネットワーク経由で他のPCからLinux上で
実行するコマンドを受け取り、armadillo側でpopen()により、そのlinuxコマンドを実行し、
実行結果をsocket経由で、他のPCへ返すというスレッドプログラムを作成しました。
しかしながら、このスレッドを1000回実行すると popen()関数からNULLが返ってきてしまい
本スレッドが続行できなくなってしまします。
(目的は "iwconfig wlan1"を実行し その結果の出力メッセージを読み取る という繰り返しを行うため。)
ネット上の情報からulimit -n 65536としましたが、変化ありませんでした。
回避策がなく、困っています。
アドバイス頂ければと思い投稿しました。
以下がソースで★が該当部分です。
void* ClientThread_51020(void* vp)
{
COMMON* common=(COMMON*)vp;
int ss;
char cmd_buf[256];
char param0[80];
char param1[80];
int i;
int j;
int counter;
char sprintf_work[4096];
time_t timer;
unsigned char *p;
int xfr_size;
pthread_t id;
struct sockaddr_in addr, caddr;
socklen_t caddr_len;
int optval, optlen;
unsigned short listen_port;
int csock;
FILE *in_pipe;
/* 読み込み用バッファ */
char buffer[BUFSIZE + 1];
int readed_num;
/* ソケットのオープン */
ss = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if ( ss < 0 ){
perror("socket");
}
optval = 1;
optlen = sizeof(optval);
/* ソケットオプション */
setsockopt(ss,SOL_SOCKET,SO_REUSEADDR,
&optval,optlen);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
signal(SIGPIPE,SIG_IGN);
/* 待ちうけport */
listen_port =PORT_51020;
addr.sin_port = htons(listen_port);
/* BIND失敗なら次のポートへ */
while(1){
addr.sin_port = htons(listen_port);
if ( bind(ss,(struct sockaddr*)&addr,sizeof(addr)) < 0 ){
perror("bind3");
listen_port++;
continue;
}else{
break;
}
}
/* リッスン */
if ( listen(ss,SOMAXCONN) < 0 ){
perror("listen");
}
/* クライントからLinuxの指令を受け取りpopenで実行 /
while(1){
caddr_len = sizeof(caddr);
/* アクセプトによりクライアントからの接続まで先へは進まない */
csock = accept(ss,(struct sockaddr*)&caddr,&caddr_len);
if ( csock < 0 ){
printf("accept error\n");
perror("accept"); continue;
}
while(1){
memset(cmd_buf,0,sizeof(cmd_buf));
//PCからの受信
if(recv(csock,cmd_buf,sizeof(cmd_buf),0)==0)
{
//PC GUIが終了されたらここ
puts("Close from PC");
break;
}
/* バッファを初期化 */
memset(buffer,'\0',sizeof(buffer));
/* パイプを読み込みモードでコマンドを実行 */
in_pipe = popen(cmd_buf,"r");
if(in_pipe==NULL){
puts("in_pipe==NULL");//★これが発生
exit (0);
}
if(in_pipe < 0){
puts("in_pipe < 0");
exit (0);
}
i=0;
memset(line_buf,0,sizeof(line_buf));
//コマンド実行結果をline_bufferに入れる
if(in_pipe != NULL){
while(fread(buffer,1,1,in_pipe) > 0){
output(buffer);
line_buf[i]=*buffer;
i++;
if(i>(sizeof(line_buf)-10))break;//line_bufを破壊防止
}
}
pclose(in_pipe);
memset(sprintf_work,0,sizeof(sprintf_work));
sprintf(sprintf_work,"%s\n", line_buf);
//PCに実行結果を送信
send(csock,sprintf_work,sizeof(sprintf_work),0);
sleep (1);
}
}
close(ss);
}
以上よろしくお願い致します。
コメント
yoshizu
斉藤様
yoshizuです
お世話になっています
puts(cmd_buf);を毎回出力しました。
in_pipe==NULLの時の1000回目も
正常な999回目と同様cmd_bufには正しく
入っていました。
51020 socket close from pc
wait loop
accept ok
iwconfig wlan1(★ 999回目)
12:22 in_pipe=103416
Close from PC
51020 socket close from pc
wait loop
accept ok
iwconfig wlan1 (★ 1000回目)
in_pipe==NULL
以上よろしくお願い致します。
> 齊藤と申します。
> とりあえず、コマンドが正常に受信できているかとどういうエラーで失敗しているかを調べてはどうでしょう。
> こんな感じ。
>
> in_pipe = popen(cmd_buf,"r");
>
> if(in_pipe==NULL){
> perror("popen");
> puts(cmd_buf);
> exit (0);
> }
y.nakamura
yoshizu
izawa
伊澤です。
本題と外れたところが気になりました。
> while(1){
> memset(cmd_buf,0,sizeof(cmd_buf));
>
> //PCからの受信
>
> if(recv(csock,cmd_buf,sizeof(cmd_buf),0)==0)
折角のrecv()の戻り値捨てちゃって大丈夫ですか?
socketは読み込み途中での復帰も有り得たと思いましたが。
# まぁ、実際にはこの件では問題出てないようですが……
> {
> //PC GUIが終了されたらここ
>
> puts("Close from PC");
>
> break;
> }
> /* バッファを初期化 */
> memset(buffer,'\0',sizeof(buffer));
>
> /* パイプを読み込みモードでコマンドを実行 */
>
> in_pipe = popen(cmd_buf,"r");
>
> if(in_pipe==NULL){
> puts("in_pipe==NULL");//★これが発生
> exit (0);
> }
> if(in_pipe < 0){
ポインタ値のマイナスチェックって?
> puts("in_pipe < 0");
> exit (0);
> }
>
> i=0;
>
> memset(line_buf,0,sizeof(line_buf));
>
> //コマンド実行結果をline_bufferに入れる
>
> if(in_pipe != NULL){
> while(fread(buffer,1,1,in_pipe) > 0){
この辺さくっとfgets()では済みませんか?
それと、1バイトしか使わないのにbuffer配列を使ったら勿体無いような。
> output(buffer);
> line_buf[i]=*buffer;
> i++;
> if(i>(sizeof(line_buf)-10))break;//line_bufを破壊防止
> }
> }
> pclose(in_pipe);
in_pipeがNULLのときも呼んでますが、
pclose()はNULLを適切に処理できましたっけ?
> memset(sprintf_work,0,sizeof(sprintf_work));
>
> sprintf(sprintf_work,"%s\n", line_buf);
これも、単にstrcpy()でいいような。
と言うかそもそもsprintf_workは要ります?
>
>
> //PCに実行結果を送信
> send(csock,sprintf_work,sizeof(sprintf_work),0);
これは明らかに余計なナル文字を送っちゃいますね。
> sleep (1);
>
>
> }
line_bufはグローバルなんでしょうか。まさかとは思いますが、
他の非同期で走る処理とバッティングしてませんよね。
スタックにKB単位で確保してその度にクリアするなんて
「配列を取り敢えずクリアしてからそこに放り込めば大丈夫」
って戦略は幾らメモリにも余裕のあるアルマジロとはいえ
資源の乏しい組み込み向けの戦略じゃない気がします。
実際、文字列として扱うのかバイト列として扱うのか
切り分けができていないからこそのsend()の問題ですし。
企業文化もあるのであれこれ言いたくはありませんが……
yoshizu
伊澤様
yoshizuです
いろいろ指摘ありがとうございます
ソースを見直してみます。
> 伊澤です。
>
> 本題と外れたところが気になりました。
>
> > while(1){
> > memset(cmd_buf,0,sizeof(cmd_buf));
> >
> > //PCからの受信
> >
> > if(recv(csock,cmd_buf,sizeof(cmd_buf),0)==0)
> 折角のrecv()の戻り値捨てちゃって大丈夫ですか?
> socketは読み込み途中での復帰も有り得たと思いましたが。
> # まぁ、実際にはこの件では問題出てないようですが……
>
> > {
> > //PC GUIが終了されたらここ
> >
> > puts("Close from PC");
> >
> > break;
> > }
> > /* バッファを初期化 */
> > memset(buffer,'\0',sizeof(buffer));
> >
> > /* パイプを読み込みモードでコマンドを実行 */
> >
> > in_pipe = popen(cmd_buf,"r");
> >
> > if(in_pipe==NULL){
> > puts("in_pipe==NULL");//★これが発生
> > exit (0);
> > }
> > if(in_pipe < 0){
> ポインタ値のマイナスチェックって?
>
> > puts("in_pipe < 0");
> > exit (0);
> > }
> >
> > i=0;
> >
> > memset(line_buf,0,sizeof(line_buf));
> >
> > //コマンド実行結果をline_bufferに入れる
> >
> > if(in_pipe != NULL){
> > while(fread(buffer,1,1,in_pipe) > 0){
> この辺さくっとfgets()では済みませんか?
> それと、1バイトしか使わないのにbuffer配列を使ったら勿体無いような。
>
> > output(buffer);
> > line_buf[i]=*buffer;
> > i++;
> > if(i>(sizeof(line_buf)-10))break;//line_bufを破壊防止
> > }
> > }
> > pclose(in_pipe);
> in_pipeがNULLのときも呼んでますが、
> pclose()はNULLを適切に処理できましたっけ?
>
> > memset(sprintf_work,0,sizeof(sprintf_work));
> >
> > sprintf(sprintf_work,"%s\n", line_buf);
> これも、単にstrcpy()でいいような。
> と言うかそもそもsprintf_workは要ります?
>
> >
> >
> > //PCに実行結果を送信
> > send(csock,sprintf_work,sizeof(sprintf_work),0);
> これは明らかに余計なナル文字を送っちゃいますね。
>
> > sleep (1);
> >
> >
> > }
> line_bufはグローバルなんでしょうか。まさかとは思いますが、
> 他の非同期で走る処理とバッティングしてませんよね。
>
> スタックにKB単位で確保してその度にクリアするなんて
> 「配列を取り敢えずクリアしてからそこに放り込めば大丈夫」
> って戦略は幾らメモリにも余裕のあるアルマジロとはいえ
> 資源の乏しい組み込み向けの戦略じゃない気がします。
> 実際、文字列として扱うのかバイト列として扱うのか
> 切り分けができていないからこそのsend()の問題ですし。
>
> 企業文化もあるのであれこれ言いたくはありませんが……
saitoh
2016年2月24日 10時42分
齊藤と申します。
とりあえず、コマンドが正常に受信できているかとどういうエラーで失敗しているかを調べてはどうでしょう。
こんな感じ。
in_pipe = popen(cmd_buf,"r");
if(in_pipe==NULL){
perror("popen");
puts(cmd_buf);
exit (0);
}