130 likes | 301 Views
ソケット及び TCP/IP を用いた ネットワークプログラミングの基礎. 平成 18 年 4 月 17 日 B5 小池 和洋. テキストファイルの転送. サンプル プログラム 小文字を大文字へ変換. 1. クライアントから小文字を含んだ文字列を送信 2. サーバからの応答. “ abCde ”. クライアント. サーバ. “ ABCDE ”. テキストファイルの転送. サンプルプログラムの改良. 1.指定したテキストファイルの中身を読み出す。 2.該当するファイルがない場合はエラーを返す。 3.複数のクライアントからの要求を
E N D
ソケット及び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=…) { ・・・ } /* クライアントとのデータのやり取り */ while ((n = …) { ・・・ } close(client_fd); close(fd); return 0; } main() { ・・・ while(1) { parent(fd); } close(fd); return 0; } int parent(int fd) { } int child(int client_fd) { } サンプルからの変更(サーバ) 関数parentとして定義 無限ループ 関数childとして定義
サーバ • 親プロセス 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); fclose(fp); } 指定されたファイルを 読み出す ファイルがなければ エラー表示 /* 終了 */ close(client_fd); 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); return 1; } if (strcmp(buf, “file open error!”) == 0) { fprintf(stderr, “%s\n”, buf) close(fd); return 0; } サーバから返ってきた文字列を bufに読み込む ファイルがなければ file open error! と返ってくる /* サーバの子プロセス */ 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で終わるようになっているが、他の終わり方にしたい。 • バイナリファイルにも適応できるようにする