• ベストアンサー

tcpを使った カウンタプログラム

サーバーをデーモンで常駐させてクライアントからの接続要求を確立した段階で、data.txt のデータベース(もどき)へ直アクセスしそこに書かれている数値をインクリメントするプログラムを作成しました。 どうか、以下のプログラムを参照してください。 http://userlocalhost.web.fc2.com/ 使用している端末の環境は 2.6.11-1.1369_FC4 です。 xinetd で監視させないで、スタンドアローンでサーバープログラムを動作させ、クライアントから接続要求を送ると、サーバープログラムのrecord() 関数に入って、 データの読み込み ↓ データをインクリメント ↓ データを更新 という流れで期待どおりの動作をしてくれるのですが、デーモンで常駐させると、record()関数に入らないのか、データがインクリメントされて更新されません。 もう一つ問題点として、サーバープログラム又はクライアントプログラムのいずれかをプログラムが置いてあるディレクトリよりも上の階層で実行した場合、プログラムが置いてあるディレクトリよりも遠い場所から実行したばあい、そのプログラムはセグメンテーションエラーになってしまいます。 推論として。これと最初の問題点の相関が強く、別々のファイルから同時に同じファイルへアクセスしているのがマズイ(原因)のかもしれないと思い、クライアントプログラムのmain() 内のcheck() をコメントアウトしたのですが、同様にセグメンテーションエラーが出てしまい、問題点と解決策がわからず、困っております。 どうか、問題解決の答えないしヒントを教えてください。

質問者が選んだベストアンサー

  • ベストアンサー
  • BIGT
  • ベストアンサー率42% (12/28)
回答No.7

例えばxinetdを使用した簡単なechoサーバは、こんな風に書く事が出来ます。 ※半角スペースだとインデントが崩れるので全角スペースでインデントしています。 #include <stdio.h> int main(void) {   int c;   while ((c = getchar()) != EOF)     putchar(c);   return 0; } 見て分かるとおり、ソケット関係の処理は一切含んでいません(xinetdが行うため)。 問題のプログラムですが、ようやく見れるようになったので確認させていただきました。server.cのmain()を下記のように書き換えれば、とりあえずはうまくいくのではないかと思います(未チェックです)。 int main(int argc, char **argv) {   FILE *fp;   /* ファイルへ結果を出力する */   if ((fp = fopen("/home/gakusei/programming/usb/test/sample03/sample.txt", "a")) == NULL) {     exit(1);   }   record(fp);   fclose(fp);   return 0; }

user_localhost
質問者

お礼

ありがとうございます。 デーモンで期待どおりの動作が出来ました。 xinetd について深い理解だとおもいますので、しばらくそれについて調べてみます。 又、tatsu99 さんも長きに渡り回答してくださり本当にありがとうございました。

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (6)

  • BIGT
  • ベストアンサー率42% (12/28)
回答No.6

「コネクション管理をプログラムではなくxinetdで行う」の意味ですが、ソケットの生成等はxinetdが処理するので、自作サーバ部分はbind()などを行う必要はないという意味です。 即ち、指定ポートはxinetdがlisten()していますので、自作サーバでこのポートにbind()しようとするとエラーになります。 従って、単独で動作するサーバをそのままxinetdの監視下に置く事は出来ません。

user_localhost
質問者

お礼

回答をくださり、ありがとうございます。 おかげで、何故システムエラーメッセージで Address already in use が出てくるのか納得致しました。 自分はこれがxinetdの設定の問題だと思いましたが、xinetdの機能の問題であることを理解致しました。 xinetdの機能については表面(システムの流れ)的なことしか理解していませんでした。 問題は、プログラムをどう書き換えるか。答えはxinetdの機能を深く知ることに他ならないのかもしれませんが。この問題を解決するためのヒントをいただけませんでしょうか。

全文を見る
すると、全ての回答が全文表示されます。
  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.5

>デーモンで接続を受けた場合には、 bind のエラーが出力されました。 bindの戻り値 及びそのときのerrnoを提示してください。 errnoにはbindエラーの理由が設定されているはずです。 又、どのようにして「デーモンで接続を受けた場合」を実現したのでしょうか。そのときのスクリプトも提示してください。 本件とは、関係ありませんが、 string = (char *)calloc(BUF_LEN, sizeof(char)); で確保したメモリを解放していません。もし、デーモンで正常に動作するようになると、次に、これが原因で、メモリの枯渇が発生します。必ず、解放するか、 char string[BUF_LEN]; memset(string,0x00,sizeof(string)); のようにして、メモリをアロケートしないことをすすめます。

user_localhost
質問者

お礼

回答をくださり、ありがとうございます。 手直ししたファイルをアップしました。 変更点は、 ・システムエラーメッセージを標準出力ではなく、ファイルへ出力した点。 ・printf() の内容を fputs() に変更し、標準出力への情報をファイルへ出力させた点。 ・文字列用の動的に確保したメモリ領域をmain() の最後で開放した点。 です。 bindのエラーは、xinetd のデーモンで実行した場合、システムエラーメッセージをファイル(sample.txt)へ出力すると、 Address already in use と出力されました。 これは、既に使用されているポートを使用してプログラムを実行させた場合に出力されるものだと思います。 つまり、これが出力されるということは、xinetd で監視してサーバープログラムを走らせると、既に5000板ポートを使っている状態でプログラムが実行されるので、このような問題が起こるのではないかと、推理できます。 そうなると、xinetd の設定の問題なのでしょうか。 /etc/xinetd.d/ 以下の設定ファイル(/etc/xinetd.d/tcp_server)の中身を記載させていただきます。 service tcp_server { disable = no flags = REUSE socket_type = stream wait = no user = root server = /home/gakusei/programming/usb/test/sample03/secondserver log_on_failure += USERID } 又、以下に /etc/xinetd.conf の内容も記載させていただきます。 defaults { instances = 60 log_type = SYSLOG authpriv log_on_success = HOST PID log_on_failure = HOST cps = 25 30 } includedir /etc/xinetd.d 更に、/etc/services には、以下のような内容を追記しました。 tcp_server 5000/tcp 以上のように設定し、xinetd を再起動させ、スタンドアローン時と同様に5000番ポートを使用してクライアントプログラムを実行させ、サーバープログラムへ接続要求を行いました。 手間をかけさせてしまい、申し訳ありません。 御回答のほど、よろしくお願い致します。

user_localhost
質問者

補足

/etc/xinetd.d/tcp_server のサーバープログラムに ..../sample03/secondserver と書きましたが、内容はオリジナルの質問のソースが置いてあるURLのserver.c をコンパイル/リンクしたものです。

全文を見る
すると、全ての回答が全文表示されます。
  • BIGT
  • ベストアンサー率42% (12/28)
回答No.4

こちらの環境からソースコードが見えないので見当違いな指摘かもしれませんが、xinetdを使用するならコネクション管理はxinetd側で行うので、自作サーバプログラムはコネクション管理を行う必要はありません。クライアントからの要求をstdinで受け取って、クライアントへの返答をstdoutにするだけで大丈夫なはずです。

user_localhost
質問者

お礼

回答くださり、ありがとうございます。 特定のプログラムでデーモンで監視されたサーバープログラムへアクセスした時の動作の実験プログラムでして、どうしてもこの形で、サーバープログラムを動作させたいのです。 又、何故スタンドアローンで正常に動作しているサーバープログラムが、xinetdで監視させると bind でエラーになるのかが気になって仕方がないのです。 残念ながら「コネクション管理をプログラムではなくxinetdで行う」と仰る意味がよくわからないので、もう少しヒントをいただけると幸いです。

全文を見る
すると、全ての回答が全文表示されます。
  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.3

#1です。本件、関係ないかもしれませんが、5000のポートは、予約されているポート番号です。他のポート番号の方が、安全かと思われます。参考URLに予約済みのポート一覧がありますので参考にしてください。

参考URL:
http://www.vwnet.jp/mura/tcpip-port.htm
全文を見る
すると、全ての回答が全文表示されます。
  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.2

#1です。ソースをみて、気がついた点です。 問題点1 if((rfp = fopen("data.txt","r")) <0) ではなく if((rfp = fopen("data.txt","r")) == NULL)としてください(ファイル名は絶対パスに読み替えてください。以下同様) fopenの失敗はNULLが返ります。 問題点2 同一のファイルを同時にオープンするのは、問題があります。 fopen("data.txt","r")) でオープンしたファイルは、 読み込み完了後、即座にcloseしてください。 その後、fopen("data.txt","w"))でオープンしてください。 問題点3 listenのエラー判定をしていない。 エラーチェックをいれてください。 問題点4 acceptのエラー判定をしていない。 エラーチェックをいれてください。 上記の修正をしても、改善しない場合は、再度補足してください。 又、エラーが発生したときに、エラーの内容を標準出力(又は標準エラー)に出力していますが、これを常駐プロセスにすると、標準出力に出力したものが、ロストしますので、特定のファイル(自前のログファイル)に出力させるようにしたほうが、さらに障害の切り分けができると考えます。

user_localhost
質問者

補足

ありがとうございます。 ご指摘の通り、エラーメッセージをファイルへ出力することで、見えて来なかった原因が見えて来ました。 サーバープログラムをスタンドアローンで起動し、クライアントから接続を受けた場合には期待どおりの結果が出力されますが、デーモンで接続を受けた場合には、 bind のエラーが出力されました。 しかしながら、何故bind で問題が発生しているのかがわかりません。 スタンドアローンでは接続成功しているので、xinetdの問題なのか。しかし、xinetdが正常に動作しているので、サーバープログラムがクライアント要求に対して起動しているわけですが…

全文を見る
すると、全ての回答が全文表示されます。
  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.1

まだ、ソースを詳しく見てませんが、とりあえず以下の点をされては、如何でしょうか? 1.ファイ名を絶対パスで指定する。 fopen("data.txt","r")ではなく、fopen("xxx/yyy/data.txt","r")のようにする。 2.-g オプションをつけてコンパイルすると、デバッグオプションでコンパイルしたことになります。 セグメンテーションエラーが発生すると、coreファイルが作成されるので、それをgdbで参照すると、どこでセグメンテーションエラーが発生したか判ります。 gdb(GNU デバッガ)がインストールされていることが、前提ですが。

user_localhost
質問者

お礼

回答くださり、ありがとうございます。 1の御指摘の通り、絶対パスでファイルをオープンしたら、セグメンテーション違反が発生しなくなりました。 そして、どのディレクトリからサーバー及びクライアントプログラムを走らせても、スタンドアローンでは期待どおりの動作をしてくれます。 しかし新たな問題として。xinetd デーモンで監視させると、今度はコネクションを確立してくれなくなりました。所有ユーザーはプログラム自体はローカルユーザーで、アクセス権限は644です。 又、/etc/xinetd.d 以下に設定したデーモンのサービスのユーザー名はroot に設定しました。 又、この問題とは無関係だと思いますが、データ(data.txt)の所有者はローカルユーザーで、アクセス権限は664です。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • TCPによるファイル転送

    質問です。よろしくお願いします。 いま、winsockでクライアントからサーバにバイナリファイルを転送するプログラムを組んでいます。内容は、サーバ側を待機の状態にし、クライアントからの要求があった時点で新たにソケットを作ってそこからデータのやり取りをするというものです。 しかし、ソケットを使った通信がサーバからクライアントの一方通行になってしまっていて、データを送ることが出来ません。(クライアントから送ったデータは0になっているようにも思われます) ソケットは一方通行なのでしょうか?参考にしている本のサンプルではお互いにやり取りをしていたと思うので、そのようなことはないと思うのですが・・・。 内容分かりにくければご質問ください。 回答お待ちしています。

  • [UNIX]NFSクライアントでのrpcbind起動の意味

    いつも勉強させてもらっております。 HP-UX(UNIX)について質問させてください。 NFS(Network File System)についてになります。 NFSにはサーバとクライアントという役割が二つ存在しますが、 サーバ側には、NFSサーバデーモンを起動させると、「rpcbind」というポート111を空けてクライアントからの要求を待ちうけ、要求に応じたプログラムを実行させるデーモンがあがります。 一方、クライアント側でも、NFSクライアントデーモンを起動させると、同じく「rpcbind」が起動されます。 クライアント側でのrpcbindが起動する理由とはなんなのでしょうか。

  • TCP通信

    OS:Win2000、VisualBasic.netで開発しています。 現在TCP通信のプログラムを製造しています。 TCPサーバとTCPクライアントのテストアプリケーションを作成し、接続テストを行っているのですが、 サーバとクライアントの接続、データ送受信の確認はできました。 しかし、一度クライアント側から接続を切断(ソケットを消去)し、 再びソケットを生成してコネクト要求を出しても接続が確立できません。 このときサーバ側はなにも操作していません。 終始接続待機状態にしてあります。 ソースがないと分かりにくいかもしれませんが、 何か思い当たることがある方、アドバイスよろしくお願いします。

  • サーバプログラム

    C言語の初心者です。 OS : CentOS 5.3 c言語でサーバ用のプログラムを書きました。 ソケット通信で接続してきたクライアントにデータをそのまま返すと言うものです。 コンパイルしたソースが、 gcc -Wall -o example example.c だとすると、この exampleソースを サービスとして( 「デーモンとして」と言うのか? )、起動したい場合、 どのように起動すればよいのでしょうか? ./example と叩くだけだと、叩いた間だけしかプログラムは動いてくれませんよねぇ。 また、サーバプログラムの良書を教えていただけたら幸いです。 初歩的な事でしたら申し訳ないですが、 よろしくお願いします。

  • TCPサーバ bind関数のエラーについて

    簡易TCPサーバをC言語で構築しています。 サーバ側のプログラムを実行し、クライアントから要求があった(GET / HTTP/1.0)場合に文字列をクライアント側に送信します。テスト一回目は要求通りの機能を果たし無事に終了できました。しかし、1回目と同じように2回目も実行すると、bind()関数でエラーが出ます。自分では一回目の接続で使ったポートが使用され続けてしまっているので、2回目の接続が前の接続に阻まれている(?)のが原因では無いかと思うのですが、これは何が原因なのでしょうか。いくら考えても分かりません。教えて下さい。

  • サーバプログラム

    ネットワークアプリケーションとして、 複数のクライアントから接続要求を受け付けるサーバプログラムには どんなものがありますか? よろしくお願いします。

  • Javaプログラム同士のプロセス間通信について

    Java初心者です。 デーモン化したJavaプログラムとJavaサーブレット間のプロセス間通信を 行いたいと思っていますがどのようにしたものか悩み中です。 ○デーモン化したJavaプログラムは、 1、あるポートからSocket通信でデータを受信し、受信したデータをDBに格納する 2、クライアントからの要求で1で保存したデータを加工して送信 ○サーブレットプログラムでは、 上記のデーモン化プログラムの設定等をブラウザ上から変更できるようにしたいと考えています。 設定とは、例えば受信したデータを全てDBに保存せずに ブラウザから条件を設定できてフィルターするような動作に変更できたり、 また、デーモン化プログラムの動作をブラウザ上から停止、開始できるようにしたいのです。 上記の様な構成の場合にプロセス間通信をする必要があると思いますが、 どの様なプロセス間通信を使えばいいのか悩んでいます。 ほんとうは上記の様な2つのプログラムを1つのプログラムで出来ればいいなぁ~と考えているのですが、、 実現方法が判りません。。 なにか名案はございませんでしょうか? わかりづらい説明でもうしわけございません。 参考になるかわかりませんが、イメージ図を、 <イメージ図> デ  data   開  data    ク ー --------> 発 -------->  ラ タ        中         イ 鯖        鯖         アント          ↑          |          |設定変更          |       管          └--------- 理                   者 よろしくおねがいします。

    • ベストアンサー
    • Java
  • Daemonの由来、語源とは??

    サーバがクライアントからの要求をまつプロセスを「デーモン」と言いますが、これがなぜ、デーモンと呼ばれているんでしょうか。どなたか語源について御存知な方はいらっしゃいませんでしょうか。そして、その語源からデーモンの役割とのつながりを御教授宜しく御願いします。

  • TCPクライアントサーバプログラムで受信したデータを処理するには?

    javaのTCPのクライアントサーバのプログラムでよく見かけると思いますが、データをクライアントもしくはサーバから受け取ったとき、それを表示させるには  cont = true ; while (cont) { try { // 読み込み (サーバorクライアントからのデータ) int n = instr.read(buff); // System.outへの書き出し System.out.write(buff, 0, n) ;                  //↑このデータを使いたい↑ } // 以下は例外処理です catch(Exception e){ // 読み出し終了時にループも終了します cont = false ; } という風にすればできるのですが、読み込んだデータを利用して処理(具体的には文字列(String)として処理したい)するにはどうすればいいのでしょうか? プログラミングに詳しい方教えて頂けないでしょうか?

  • ConnectNamedPipeの接続待ち

    はじめまして。 名前付きパイプを用いた、 サーバ側、クライアント側のプログラムを作成しています。 開発言語はVB6.0です。 サーバ、クライアント間の接続、データの送受信など、 ある程度のことは出来るようになったのですが、ひとつ問題が発生しました。 現在、サーバ・クライアント間の接続には、 サーバ側でConnectNamedPipe関数により、クライアント側の接続を待機し、 クライアント側でCreateFile関数で接続する、という方法を取っています。 この方法で一応接続は上手くいっているのですが、 サーバ側で、クライアント側の接続を待機した状態で、 クライアント側からの接続が行われない場合、 サーバ側のプログラムはConnectNamedPipe関数で、 いつまでも待機状態になってしまい、プログラムを終了することが出来ません。 そこで、ConnectNamedPipe関数の接続待ちにタイムアウト時間を設定する、 もしくは手動でキャンセルする、ということを行いたいのですが、 良い方法が見つかりません。 どなたか分かる方いましたらご解答宜しくお願いします。