ソケット及びTCP/IPを用いた

ソケット及びTCP/IPを用いた
ネットワークプログラミングの基礎
平成18年4月17日
B5 小池 和洋
テキストファイルの転送
► サンプル
プログラム
小文字を大文字へ変換
1.クライアントから小文字を含んだ文字列を送信
2.サーバからの応答
“abCde”
クライアント
“ABCDE”
サーバ
テキストファイルの転送
► サンプルプログラムの改良
1.指定したテキストファイルの中身を読み出す。
2.該当するファイルがない場合はエラーを返す。
3.複数のクライアントからの要求を
受け入れられるようにする。
テキストファイルを読み出す
1.クライアントからファイル名を送信
2.該当するファイルを読み出す
3.ファイルの内容を送り返す
“test.txt”
クライアント
サーバ
test.txt
abcde
abcde
サンプルからの変更(サーバ)
main() {
・・・
/* クライアントからの接続を待つ */
if ((client_fd=…) {
・・・
}
関数parentとして定義
main() {
・・・
while(1) {
parent(fd);
}
close(fd);
return 0;
/* クライアントとのデータのやり取り */
while ((n = …) {
・・・
関数childとして定義
}
close(client_fd);
close(fd);
return 0;
}
無限ループ
}
int parent(int fd) {
}
int child(int client_fd) {
}
サーバ
► 親プロセス
int parent(int fd)
{
int client_fd;
/* クライアントからの接続を待つ */
if ((client_fd = accept(fd, NULL, NULL) < 0) {
perror(“accept”);
close(fd);
return 1;
}
/* forkによる子への引渡し */
}
if (fork() == 0) {
child(client_fd);
}
return 0;
この部分は
mainがそのまま
入っている
fork() = 0なら
子プロセスを作り
あとの作業をさせる
親はmainに戻り、応答を待つ
(whileによるループ)
► 子プロセス
int child(int client_fd)
{
char buf[1024], ch;
int n, i;
FILE *fp;
/* クライアントとのデータのやり取り */
while (n = read(client_fd, buf, sizeof(buf)-1)) > 0) {
buf[n] = ‘\0’;
指定されたファイルを
printf(“file: ‘%s’\n”, buf);
読み出す
/* 指定されたファイルがなければエラーを返す */
if ((fp = fopen(buf, “r”)) == NULL) {
fprintf(stderr, “file open error!\n”); /* サーバ側にも表示 */
sprintf(buf, “file open error!”, client_fd);
ファイルがなければ
write(client_fd, buf, strlen(buf));
エラー表示
return 1;
}
printf(“return to client:\n%s\n”, buf);
/* 終了 */
write(client_fd, buf, sizeof(buf)-1);
close(client_fd);
fclose(fp);
return 0;
ファイルの中身を送る
}
}
サンプルからの変更(クライアント)
main() {
FILE *fp;
char fname[64]; /* ファイル名 */
・・・
/* サーバとのデータのやり取り */
if (fgets(buf, sizeof(buf), stdin) == NULL) {
・・・
}
buf[strlen(buf)-1] = ‘\0’; /* 改行文字を消す */
printf(“send to server: ‘%s’\n”, buf);
write(fd, buf, strlen(buf)); /* 送信 */
新たに定義
サンプルからの変更(クライアント)
main() {
FILE *fp;
char fname[64]; /* ファイル名 */
・・・
/* サーバとのデータのやり取り */
if (fgets(fname, sizeof(fname), stdin) == NULL) {
・・・
}
fname[strlen(fname)-1] = ‘\0’; /* 改行文字を消す */
printf(“send to server: ‘%s’\n”, fname);
write(fd, fname, strlen(fname)); /* ファイル名の送信 */
クライアント
if (n = read(fd, buf, sizeof(buf)-1)) < 0) {
perror(“read”);
サーバから返ってきた文字列を
close(fd);
bufに読み込む
return 1;
}
ファイルがなければ
if (strcmp(buf, “file open error!”) == 0) {
file open error!
fprintf(stderr, “%s\n”, buf)
と返ってくる
close(fd);
return 0;
/* サーバの子プロセス */
}
if ((fp = fopen(buf, “r”)) == NULL) {
fprintf(stderr, “file open error!\n”); /* サーバ側にも表示 */
sprintf(buf, “file open error!”, client_fd);
write(client_fd, buf, strlen(buf));
return 1;
}
クライアント
fp = fopen(fname, “w”);
ファイルへの書き込み
fprintf(fp, “%s”, buf);
buf[strlen(buf)-1] = ‘\0’;
printf(“-----received fron server:\n%s\n-----\n”, buf);
/* 終了 */
fclose(fp);
close(fd);
return 0;
}
受け取ったテキストの中身を
画面にも表示される
実行結果
► サーバ側
► クライアント側
ファイル名指定
課題
► どんなサイズのファイルでも読み込めるように
2,3行程度のファイルもあれば、何千行も書かれたファイルもある。
1行ずつ、又は1文字ずつ読み込むように改良したい。
► サーバの終了方法を工夫する
今はCtrl+Cで終わるようになっているが、他の終わり方にしたい。
► バイナリファイルにも適応できるようにする