ソケット及び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で終わるようになっているが、他の終わり方にしたい。 ► バイナリファイルにも適応できるようにする
© Copyright 2024 ExpyDoc