質問編集履歴

1 実行できていたエラーのなかったソースの追加及び条件の明示

SioRyu

SioRyu score 11

2018/10/26 01:27  投稿

strtokの使い方およびファイルオープンエラーの解決方法
大学の授業で習っている最中なのですが、通信システムのシミュレーションをしたいプログラムで。出された課題内容がプログラムの機能を拡張するもので。一つ目の課題は特に問題なくクリアしたのですが二つ目でエラーが出てしまいどう解決すればいいかわからず、皆様に直し方をお聞きしたいです。
以前でも同じような課題が出てその課題と類似しています。
strtokでファイル名を","で区切り二つのファイル名を入力後、その二つのファイルの中に入っているものを出力するプログラムを書きたいのですがFile access errorになってしまいます。
strtokの使い方が間違っているのでしょうか?
strtokでjp.txtとch.txtに分けられておらず中身のbufもそれぞれのbut[0]とbuf[1]に格納できていないのでしょうか?
動作環境は大学のパソコンで
仮想マシンCentOS Linux socket通信環境
0. サーバー側
```c
/* コネクション型の簡単なリモートファイル表示サーバ(vc_server.c) */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h> /* ソケットのための基本的なヘッダファイル     */
#include <netinet/in.h> /* インタネットドメインのためのヘッダファイル */
#include <netdb.h>     /* gethostbyname()を用いるためのヘッダファイル */
#include <errno.h>
#include <string.h>
#define MAXHOSTNAME   64
#define S_TCP_PORT   (u_short)5000 /* 本サーバが用いるポート番号 */
#define MAXFILENAME   255
#define MAXBUFLEN   512
#define ERR       0 /* ファイルオープン失敗 */
#define    OK       1 /*                成功 */
int setup_vcserver(struct hostent*, u_short);
void send_file(int);
main()
{
   int   socd, socd1;
   char   s_hostname[MAXHOSTNAME];
   struct hostent   *s_hostent;
   struct sockaddr_in   c_address;
   int   c_addrlen, cpid;
   /* サーバのホスト名とそのIPアドレス(をメンバに持つhostent構造体)を求める */
   gethostname(s_hostname, sizeof(s_hostname));
   s_hostent = gethostbyname(s_hostname);
   /* バーチャルサーキットサーバの初期設定 */
   socd = setup_vcserver(s_hostent, S_TCP_PORT);
   while(1) {
       /* 接続要求の受け入れ */
       c_addrlen = sizeof(c_address);
       if((socd1 = accept(socd, (struct sockaddr *)&c_address, &c_addrlen)) < 0) {
           perror("accept");
           exit(1);
       }
       /* フォーク(並行サーバのサービス) */
       if((cpid = fork()) < 0) { perror("fork");exit(1); }
       else if(cpid == 0) { /* 子プロセス */
           close(socd);
           /* クライアントが要求するファイルの送信 */
           send_file(socd1);
           close(socd1);
           exit(0);
       }
       else close(socd1);  /* 親プロセス */
   }
}
int setup_vcserver(struct hostent *hostent, u_short port)
{
   int   socd;
   struct sockaddr_in   s_address;
   /* インターネットドメインのSOCK_STREAM(TCP)型ソケットの構築 */
   if((socd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket");exit(1); }
   /* アドレス(IPアドレスとポート番号)の作成 */
   bzero((char *)&s_address, sizeof(s_address));
   s_address.sin_family = AF_INET;
   s_address.sin_port = htons(port);
   bcopy((char *)hostent->h_addr, (char *)&s_address.sin_addr, hostent->h_length);
   /* アドレスのソケットへの割り当て */
   if(bind(socd, (struct sockaddr *)&s_address, sizeof(s_address)) < 0) { perror("bind");exit(1); }
   /* 接続要求待ち行列の長さを5とする */
   if(listen(socd, 5) < 0) { perror("listen");exit(1); }
   return socd;
}
void send_file(int socd) /* クライアントが要求するファイルを読み込みソケットに書き出す */
{
   char   filename[MAXFILENAME+1];
   FILE   *fd;
   char   ack;
   char   buf[i][MAXBUFLEN];
   int i=0;
   char token;
   char   **dbp
   for(;;)
   {
       /* クライアントから送られるファイル名をソケットから読み込む */
       recv(socd, filename, MAXFILENAME+1, 0);
       token = *strtok(filename, ",");
       do{
         while(*dbp){
           if(strcmp(&token, *dbp) == 0) {
           strcpy(buf[i], *(++dbp));
           break;
           }
           dbp += 1;
        }
        i++;
       }while(token == *strtok(NULL,","));
       if(*dbp == NULL) strcpy(*data, "No entry");
       /* ファイルを読み出し専用にオープンする */
       if((fd = fopen(filename, "r")) != NULL) { /* ファイルオープンに成功した場合 */
           /* オープン成功メッセージを送る */
           ack = OK;
           send(socd, &ack, 1, 0);
           /* ファイルから1行読み込みソケットに書き出すことをEOFを読むまで繰り返す */
           printf("ファイル %s を送信\n",filename);
           while(fgets(buf[i], MAXBUFLEN, fd)) {
               send(socd, buf[i], strlen(buf[i]), 0);
           }
           close(fd);
       }
       else
       {                                   /* ファイルオープンに失敗した場合 */
           /* オープン失敗メッセージを送る */
           ack = ERR;
           send(socd, &ack, 1, 0);
       }
   }
}
```
0. クライアント側
```c
/* コネクション型の簡単なリモートファイル表示クライアント(vc_client.c) */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h> /* ソケットのための基本的なヘッダファイル     */
#include <netinet/in.h> /* インタネットドメインのためのヘッダファイル */
#include <netdb.h>     /* gethostbyname()を用いるためのヘッダファイル */
#include <errno.h>
#include <string.h>
#define MAXHOSTNAME   64
#define    S_TCP_PORT   (u_short)5000
#define MAXFILENAME   255
#define    MAXBUFLEN   512 
#define    ERR       0 /* ファイルオープン失敗 */
#define OK       1 /*                成功 */
int setup_vcclient(struct hostent*, u_short);
void receive_file(int);
main()
{
   int   socd;
   char   s_hostname[MAXHOSTNAME];
   struct hostent   *s_hostent;
   /* サーバのホスト名の入力 */
   printf("server host name?: "); scanf("%s",s_hostname);
   /* サーバホストのIPアドレス(をメンバに持つhostent構造体)を求める */
   if((s_hostent = gethostbyname(s_hostname)) == NULL) {
       fprintf(stderr, "server host does not exists\n");
       exit(1);
   }
   /* バーチャルサーキットクライアントの初期設定 */
   socd = setup_vcclient(s_hostent, S_TCP_PORT);
   /* サーバにファイルを要求し受信したファイルの内容を標準出力に出力 */
   receive_file(socd);
   close(socd);
   exit(0);
}
int setup_vcclient(struct hostent *hostent, u_short port)
{
       int    socd;
       struct sockaddr_in     s_address;
   /* インターネットドメインのSOCK_STREAM(TCP)型ソケットの構築 */
       if((socd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket");exit(1); }
   /* サーバのアドレス(IPアドレスとポート番号)の作成 */
       bzero((char *)&s_address, sizeof(s_address));
       s_address.sin_family = AF_INET;
       s_address.sin_port = htons(port);
       bcopy((char *)hostent->h_addr, (char *)&s_address.sin_addr, hostent->h_length);
   /* サーバとの接続の確立 */
   if(connect(socd, (struct sockaddr *)&s_address, sizeof(s_address)) < 0) { perror("connect");exit(1); }
   return socd;
}
void receive_file(int socd) /* サーバから受け取ったファイルの内容を表示する */
{
   char   filename[MAXFILENAME+1];
   int   filename_len;
   char   ack;
   char   buf[i][MAXBUFLEN];
   int   length;
   int i;
   
   for(;;)
   {
       /* ファイル名の入力 */
       printf("remote file name?: ");
       if(scanf("%s",filename)==EOF)break;
       /* ファイル名をソケットに書き込む */
       filename_len = strlen(filename);
       send(socd, filename, filename_len+1, 0);
       /* ファイルオープンに成功したかどうかのメッセージをソケットから読み込む */
       recv(socd, &ack, 1, 0);
       switch (ack) {
       case OK: /* ファイルオープンに成功した場合 */
           printf("ファイル %s を受信\n", filename);
           /* ソケットから読み込み標準出力に書き出す */
           while(length = recv(socd, buf[i], MAXBUFLEN, 0)) {
               buf[i][length] = '\0';
               for(i=0;i<5;i++){
                 
                 fputs(buf[i], stdout);
               }
               break;
           }
           printf("\n");
           break;
       case ERR: /* ファイルオープンに失敗した場合 */
           fprintf(stderr, "File access error\n");
           break;
       }
   }
}
```
> 実行結果:
[root@skt35 Linux_share]# gcc -o client client.c
[root@skt35 Linux_share]# ./client
server host name?: skt35
remote file name?: jp.txt,ch.txt
File access error
[root@skt35 Linux_share]# gcc -o server server.c
[root@skt35 Linux_share]# ./server
//何も表示されない
//何も表示されない
サーバー側(第一課題を実行できていたもの)
```c
void send_file(int socd) /* クライアントが要求するファイルを読み込みソケットに書き出す */
{
   char   filename[MAXFILENAME+1];
   FILE   *fd;
   char   ack;
   char   buf[MAXBUFLEN];
   for(;;)
   {
       /* クライアントから送られるファイル名をソケットから読み込む */
       recv(socd, filename, MAXFILENAME+1, 0);
       /* ファイルを読み出し専用にオープンする */
       if((fd = fopen(filename, "r")) != NULL) { /* ファイルオープンに成功した場合 */
           /* オープン成功メッセージを送る */
           ack = OK;
           send(socd, &ack, 1, 0);
           /* ファイルから1行読み込みソケットに書き出すことをEOFを読むまで繰り返す */
           printf("ファイル %s を送信\n",filename);
           while(fgets(buf, MAXBUFLEN, fd)) {
               send(socd, buf, strlen(buf), 0);
           }
           close(fd);
           printf("\n");
       }
       else
       {                                   /* ファイルオープンに失敗した場合 */
           /* オープン失敗メッセージを送る */
           ack = ERR;
           send(socd, &ack, 1, 0);
       }
   }
}
```
クライアント側(第一課題を実行できたもの)
```c
void receive_file(int socd) /* サーバから受け取ったファイルの内容を表示する */
{
   char   filename[MAXFILENAME+1];
   int   filename_len;
   char   ack;
   char   buf[MAXBUFLEN];
   int   length;
   for(;;)
   {
       /* ファイル名の入力 */
       printf("remote file name?: ");
       printf("what");
       if(scanf("%s",filename)==EOF)break;
       printf("at");
       /* ファイル名をソケットに書き込む */
       filename_len = strlen(filename);
       printf("that");
       send(socd, filename, filename_len+1, 0);
       printf("chat");
       /* ファイルオープンに成功したかどうかのメッセージをソケットから読み込む */
       recv(socd, &ack, 1, 0);
       printf("hat");
       switch (ack) {
       case OK: /* ファイルオープンに成功した場合 */
           printf("ファイル %s を受信\n", filename);
           /* ソケットから読み込み標準出力に書き出す */
           while(length = recv(socd, buf, MAXBUFLEN, 0)) {
               buf[length] = '\0';
               fputs(buf, stdout);
               break;
           }
           break;
       case ERR: /* ファイルオープンに失敗した場合 */
           fprintf(stderr, "File access error\n");
           break;
       }
   }
}
```
サーバー側とクライアント側ともに最後の関数しか変更しておらず、この部分のみの状態でしたら実行できました。
今回に関しては複数の入力に対して複数の出力ができればいいので。特に","で区切らないといけないという訳でもなく、複数という条件しか出されていなかったので最小二つに対応できればいいです。
  • C

    5643 questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

  • Linux

    5332 questions

    Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

  • CentOS

    3723 questions

    CentOSは、主にRed Hat Enterprise Linux(RHEL)をベースにした、フリーのソフトウェアオペレーティングシステムです。

思考するエンジニアのためのQ&Aサイト「teratail」について詳しく知る