実験2ソフトウェア FAQ

[実験全般編] [C言語編] [Java編]

実験全般編

Q: 自作クライアント(やtelnet)で実験2ソフトウェアのページ(http://www.fos.kuis.kyoto-u.ac.jp/le2soft/)に接続すると,htmlを受信後しばらく接続が切れない.

A: ファイル送信後しばらく(15秒ほど)通信が切断されないのはサーバ側の設定の都合ですので,クライアント側の問題ではありません.しばらく待ってください.


Q: 資料中のmakeの説明どおりのMakefileを作成してmakeすると「common.hが無い」と怒られる。

A: この例は、client.c, server.cに共通のヘッダ部分をcommon.hとして分離している場合を想定しています。 common.hが存在しない場合は、common.hの部分を削除しましょう。

例えば、Makefileの
server.o: server.c common.h
という行は「server.oを作成するためには、server.cとcommon.hというソースファイルが必要」という依存関係を示しています。


Q: CGIのテストをしてみたいが、どうすればいいのかわからない。

A: 簡単な実行可能ファイルを用意しましょう。
例えばCで簡単な("Hello world."のような)プログラムを作ってコンパイルしておいたり、下のような簡単なシェルスクリプトを用意してみましょう。

例 (ls.cgi)
#!/bin/sh
ls -lR $HOME

実行権限を出しておくことを忘れないように。

% chmod +x ls.cgi


Q: 資料のHTTPの文法定義と、その後の例が合致していない。

A: 課題2の文法定義では、

request-header = "Host" ":" host [ ":" port ]

となっていますが、その直後の例では、

HOST: www.hogehoge.com:80

と、HOST:の後に空白文字が入っています。
正しくは定義の通り、HOST:の後に空白を入れる必要はありませんが、入れてもその空白を無視するように実装されているのが普通なようです。(参考資料の
4.2章 メッセージヘッダでは、このような空白は削除される「であろう」と書いてあります:-( )
この実験では、空白を入れても入れなくてもかまいません。とくにサーバ側では、どちらか一方のやり方のみを受理できればよいものとします。


Q: サーバのレスポンスのヘッダ (entity-header) として何を返すべきかわからない。

A: 本来は、送信するファイルの文字コードやファイルの種類などを識別してヘッダを作成すべきですが、この実験では全て固定(例えば実行例にあるように、media-typeは"text/html"、charsetは"us-ascii")してしまっても構いません。


C言語編

Q: fdopen で +r や +w を使って読み込みと書き込みを切り替えて使いたいが2回目以降うまくいかない.

A: 読み込みと書き込みを切り替えるときには,必ず fflush(fp) を呼び出しましょう.

例:
FILE *fp;

fp=fdopen(s,"r+");

fgets(buf, sizeof(buf), fp);

fflush(fp);
fputs(buf, fp);

fflush(fp);
fgets(buf, sizeof(buf), fp);


Q: コマンドへの引数の渡し方がわからない.

A: 例えば、serverコマンドを、ポート番号を引数として

% server 60001

などと実行させたい場合、この「60001」のような引数はmain関数の引数として渡すことができます.

例:
int main(int argc, char *argv[]) {
...
}

このようにすると、argcに「引数の個数」が、argvに「引数の列(文字列の配列として)」が格納されます。
この場合、実行しようとしているコマンド名自体も「0番目の引数」として扱われるので注意が必要です。上の例をコンパイルして実行ファイルexampleを作成し、

% example abc def

と実行すると、mainの本体において、argcの値は「3」に、配列argvの値は0番目が「example」、1番目が「abc」、2番目が「def」という文字列になります。


Q: fgetsでメッセージを受け取ろうとしているが、メッセージの最後まで受け取ってもさらに待ち続けてしまう。

A: fgets は、文字列が引数で指定したサイズに到達するまでは、改行文字などの行の終端を表す記号を読み込まない限り、読み込みを継続しようと待ち続けます。ですので、メッセージを送信する側で、メッセージの終端を改行記号などにしておかないと、fgetsは送信の終了を認識できません。

例えば、

client.c:
...
send(s, "Message", 7, 0);
...

server.c:
...
fgets(buf, sizeof(buf), f);
...

などで、サーバが受け取った文字列 Message をbufに格納しようとすると、fgetsは Message を読み込んだ後、さらなる入力を待ち続けます。
文字列 Message を受信した段階でbufに格納したい場合は、送信側で"Message\n"と改行文字をつけて送信する(この場合、サーバ側で改行文字を再度取り除く必要がある)か、または、sendするバイト数を8とするなどして文字列の終端文字を含めて送信することにより、fgetsにメッセージが終了したことを伝える必要があります。


Q: 実行を遅らせたい。

A: サーバが複数クライアントに対応していることをチェックするためには、例えばファイルの送信時に一行ごとに待ち時間を挿入して表示を遅らせればよいでしょう。このためには、Cのsleep関数が使えます。

例(fooを出力後、1秒待ってからbarを出力する):
printf("foo\n");
sleep(1);
printf("bar\n");


Q: sendで送信したデータがうまく受信できない。

A: 一つの原因として考えられるのは、sendの引数で指定しているサイズの扱いを誤っていることです。
sendでは、終端記号か否かに関係なくきっちり指定したサイズを送信します。
一方、fgetsなどの関数では、改行などの終端記号までの文字列を送受信し、その際指定されるサイズは、そのような終端記号が文字列に含まれない場合の「上限」のサイズだと理解でき、sendの場合とは意味が異なります。

対応策としては次が考えられます。
(1) sendでのサイズ指定は send(buf,sizeof(buf),fp) などとせずに、send(buf,strlen(buf),fp)などとする。(sizeofを使うと、bufの長さに足りない部分はメモリ上の予期しない内容が送信されてしまう。)
(2) sendではなく、fputsなどを利用する。


Q: マニュアルを見るために"man accept"としても、関係のないacceptの説明が出る。

A: manページは同名の異なるコマンド・関数を区別するためにセクションと呼ばれる番号で区別されています。実験の環境で"man accept"とすると、セクション8(管理用ツール)のaccept(8)のマニュアルが表示されます。システムコールのacceptを指定するためには、明示的にセクション番号2(システムコール)を与えて

% man 2 accept

とします。


Java編


[
HOME]