teratail header banner
teratail header banner
質問するログイン新規登録

質問編集履歴

2

問題文の要約

2019/08/08 19:02

投稿

tosakasimon
tosakasimon

スコア8

title CHANGED
File without changes
body CHANGED
@@ -1,35 +1,5 @@
1
- ### 複数クライアント接続対応のチャットサーバープログラム
1
+ ### 複数クライアント接続
2
2
 
3
- linux環境下のc言語を用いて複数クライアント接続対応のサーバプログラムを作成しているのですがあまりうまく行きません。他者が作成したクライアントプログラムとも通信をするために以下のようなプロトコル仕様があります。
4
- クライアントの仕様
5
-
6
- [状態c1](初期状態)ソケットを生成し(socket),引数で指定されたホストへ接続要求を出す(connect).[状態c2]へ移る.
7
-
8
- [状態c2](参加)サーバから17文字のメッセージを受信する(read).もしメッセージが接続受理("REQUEST ACCEPTED\n")ならば状態c3へ,さもなければ(接続拒否または何らかの例外)[状態c6]へ移る.
9
-
10
- [状態c3](ユーザ名登録)引数で指定されたユーザ名(最後に改行)を送信する.(write)続いて20文字の文字列を受信し(read),受信文字列が登録完了メッセージ("USERNAME REGISTERED\n")であれば,[状態c4]へ,さもなければ,エラーメッセージを表示し,[状態c6]へ移る.
11
-
12
- [状態c4](メッセージ送受信)標準入力とサーバ両方の入力を待ち(select),標準入力からの文字列はサーバへ送信し(write),サーバからの受信文字列は標準入力へ出力する(read).標準入力がEOFなら[状態c5]へ,さもなければ[状態c4]へ移る.
13
-
14
- [状態c5](離脱)ソケットを閉じて(close),クライアントプログラムを正常終了する(exit(0)).
15
-
16
- [状態c6](例外処理)ソケットを閉じて(close),クライアントプログラムを異常終了する(exit(1)).
17
-
18
- サーバ側のプロトコル仕様状態
19
-
20
- [s1](初期状態)ソケットを生成(socket)し,接続要求を待つように設定する(bind,listen).参加クライアント数kを0に初期化する.[状態s2]へ移る.
21
-
22
- [状態s2](入力待ち)接続要求を待つソケットからの入力,および,参加しているすべてのクライアントのソケットからの入力3を一定時間監視する(select).[状態s3]へ移る.
23
-
24
- [状態s3](入力処理)入力があったすべてのソケットに対して入力処理を行う.接続要求あり:[状態s4]へ移る.クライアントi(i= 1; : : : ; k)から入力あり:[状態s6]へ移る.入力があったソケットすべてに対して処理を終えたら[状態s2]へ移る.
25
-
26
- [状態s4](参加受け付け)接続要求を受理する(accept).次に,もし現在の参加クライアント数kがMAXCLIENTS未満であれば,接続受理のメッセージ(文字列"REQUEST ACCEPTED\n")を返し(write),クライアントソケット4をk+ 1番目のクライアントとして登録し,[状態s5]へ移る.さもなければ接続拒否のメッセージ(文字列"REQUEST REJECTED\n")を返し(write),クライアントソケットを閉じて(close),[状態s3]へ移る.
27
-
28
- [状態s5](ユーザ名登録)\ユーザ名+改行"を受信し(read),1~k番目のユーザのいずれかと同じ名前ならば,登録拒否のメッセージ(文字列"USERNAME REJECTED\n")を返し(write),登録拒否したユーザ名を分かりやすく標準出力に出力し,クライアントソケットを閉じて(close),[状態s3]へ移る.未登録のユーザならば,k+1番目のクライアントのユーザ名として登録する.登録完了メッセージ(文字列"USERNAME REGISTERED\n")を送信し(write),登録したユーザ名を分かりやすく標準出力に出力し,kを1増やす.[状態s3]へ移る.
29
-
30
- [状態s6](メッセージ配信)クライアントiから文字列を入力する(read).もしEOFならば[状態s7]へ移る.さもなければその入力文字列の先頭にユーザ名を追加して,全クライアントに対して送信し(write),[状態s3]へ移る.
31
-
32
- [状態s7](離脱処理)クライアントiのソケットを閉じる(close).離脱したユーザ名を分かりやすく標準出力に出力し,クライアント数kを1減らすなどの離脱処理を行い,[状態s3]へ移る
33
3
  ###問題
34
4
 
35
5
  ```

1

文法の大幅修正

2019/08/08 19:01

投稿

tosakasimon
tosakasimon

スコア8

title CHANGED
File without changes
body CHANGED
@@ -33,7 +33,8 @@
33
33
  ###問題
34
34
 
35
35
  ```
36
+ ユーザー名の登録などがうまく行かないです。空白文字で区切ったりしてはいるのですが。
36
- 状態遷移などがうく行かないです。サーバプログラムを実行し、クライアントから、サーバー側端末名、クライアント側のゲスト名引数にて実行したら、最初にREQUEST承認の是非やユーザー確認作業にはいるはずが、if(FD_ISSET〜以降のソケットからの入力処理ところ入ってしまいます。
37
+ 、クライアントがEOF入力したら、のユーザーののソケットを閉じて入力、受付待ちに戻るはずなですが、ユーザー名を大量出力し作業が強制的に終了てしまいます。
37
38
  ```
38
39
 
39
40
  ### schat.c(サーバプログラム)
@@ -61,8 +62,9 @@
61
62
  struct sockaddr_in clt;
62
63
  struct sockaddr_in svr;
63
64
  struct hostent *cp;
64
- int clen,nbytes,kmax;
65
+ int clen,nbytes,fdmax,flag;
66
+ int Nbyte[5];
65
- char USERNAME[5][32];
67
+ char USERNAME[5][32],Nbuf[32];
66
68
  fd_set rfds;/* select()で用いるファイル記述子集合*/
67
69
  struct timeval tv;
68
70
  char rbuf[128],buffer[128],*arg;
@@ -90,93 +92,83 @@
90
92
  perror("listen");
91
93
  exit(1);
92
94
  }
93
-
94
- while(1){/*入力を監視するファイル記述子の集合を変数rfdsにセットする*/
95
+ while(1){
95
96
  FD_ZERO(&rfds);
96
- FD_SET(0,&rfds);
97
97
  FD_SET(sock,&rfds);
98
- kmax=sock;
98
+ fdmax=sock;
99
- clen=sizeof(clt);
100
-
101
- fprintf(stderr,"01\n");
102
- for(h=0;h<MAXCLIENTS;h++){
99
+ for(int i=0;i<MAXCLIENTS;i++){
103
- if(csock[h]!=-1){
100
+ if(csock[i]>0){
104
- FD_SET(csock[h],&rfds);
105
- if(csock[h] > kmax ) {
101
+ if(csock[i]>fdmax){
106
-
107
- kmax = csock[h];
102
+ fdmax=csock[i];
108
- write(csock[h],"1connected\n",9);
109
- write(1,"connected\n",9);
110
- printf(" \n");
111
-
112
- if(sock==MAXCLIENTS-1){
113
- write(sock,"REQUEST REJECTED\n",17);
114
- close(sock);
115
- continue;
116
- }else if(sock<MAXCLIENTS-1){
117
- write(sock,"REQUEST ACCEPTED\n",17);
118
- read(sock,rbuf,sizeof(rbuf));
119
- for(int i=0;i<5;i++){
120
- if(strcmp(rbuf,USERNAME[i])==0){
121
- write(sock,"USERNAME REJECTED\n",18);
122
- close(sock);
123
- continue;
124
- }else{
125
- strcpy(USERNAME[i],rbuf);
126
- write(sock,"USERNAME REGISTERED\n",20);
127
- sock++;
128
- }
129
- }
130
- }
131
-
132
103
  }
104
+ FD_SET(csock[i],&rfds);
133
105
  }
134
106
  }
135
- /*監視す る待ち時間を1秒に設定*/
136
107
  tv.tv_sec = 1;
137
108
  tv.tv_usec = 0;/*標準入力とソケットからの受信を同時に監視する*/
109
+ section3:
138
- if(select(kmax+1,&rfds,NULL,NULL,&tv)>0) {
110
+ if(select(fdmax+1,&rfds,NULL,NULL,&tv)>0){
139
-
140
- if(FD_ISSET(sock,&rfds)) {
111
+ if(FD_ISSET(sock,&rfds)){
141
- for(int i=0;i<k;i++){
112
+ for(int i=0;i<MAXCLIENTS;i++){
142
- fprintf(stderr,"02\n");
143
- if(csock[i]<0){
113
+ clen=sizeof(clt);
144
- if ( ( csock[i] = accept(sock,(struct sockaddr *)&clt,&clen) ) <0 ) {
114
+ if ( ( csock[i] = accept(sock,(struct sockaddr *)&clt,&clen) ) <0 ) {
145
- perror("accept");
115
+ perror("accept");
146
- exit(2);
116
+ exit(2);
147
- }
117
+ }
118
+ if(sock<MAXCLIENTS){
148
- fprintf(stderr,"03\n");
119
+ write(csock[i],"REQUEST ACCEPTED\n",17);
149
120
  nbytes=read(csock[i],rbuf,sizeof(rbuf));
121
+ strncpy(Nbuf,rbuf,nbytes-1);
122
+ Nbyte[i]=nbytes;
123
+ flag=0;
150
- for(int j=0;j<k;j++){
124
+ for(int j=0;j<MAXCLIENTS;j++){
151
- fprintf(stderr,"04\n");
125
+ if(strcat(USERNAME[j],Nbuf)==0){
126
+ flag=1;
152
- char usr_1[128]="<";
127
+ char name[32]="REJECTED";
153
- char usr_2[]="<";
128
+ write(csock[i],"USERNAME REJECTED\n",18);
154
- strcat(usr_1,USERNAME[i]);
155
- strcat(usr_1,usr_2);
156
- strcat(usr_1,rbuf);
129
+ strcat(name,Nbuf);
130
+ for(int k=0;k<MAXCLIENTS;k++)
157
- write(csock[j],usr_1,sizeof(usr_1));
131
+ write(csock[k],name,sizeof(name));
132
+ close(csock[i]);
133
+ goto section3;
134
+ }
158
135
  }
136
+ if(flag==0){
137
+ write(csock[i],"USERNAME REGISTERED\n",20);
138
+ strncpy(USERNAME[i],Nbuf,Nbyte[i]-1);
139
+ char nll[]="\0";
140
+ strcat(USERNAME[i],nll);
141
+ write(1,USERNAME[i],sizeof(USERNAME[i]));
142
+ k++;
143
+ goto section3;
144
+ }
145
+
146
+
159
147
  }
160
148
  }
161
-
162
149
  }
163
- for(int i=0;i<k;i++){
150
+ for(int i=0;i<MAXCLIENTS;i++){
164
151
  if(FD_ISSET(csock[i],&rfds)){
165
- if(read(csock[i],rbuf,sizeof(rbuf))!=EOF){
152
+ if(read(csock[i],rbuf,sizeof(rbuf))!=0){
153
+ char STRING[64]="<";
154
+ strcat(STRING,USERNAME[i]);
155
+ strcat(STRING,"\0");
156
+ strcat(STRING,">");
166
- close(csock[i]);
157
+ strcat(STRING,rbuf);
167
-
158
+ for(int j=0;j<MAXCLIENTS;j++){
159
+ write(csock[j],STRING,sizeof(STRING));
160
+ }
168
161
  }else{
169
- nbytes=read(csock[i],rbuf,sizeof(rbuf));
170
- if(nbytes<=0)exit(1);
162
+ fprintf(stderr,"01\n");
171
-
172
- write(0,rbuf,nbytes);
163
+ close(csock[i]);
173
- for(int j=0;j<k;j++){
164
+ for(int j=0;MAXCLIENTS;j++){
174
- if(j!=i){
175
- write(csock[j],rbuf,nbytes);
165
+ write(csock[j],USERNAME[i],sizeof(USERNAME[i]));
176
- }
177
166
  }
167
+ USERNAME[i][0]='\0';
168
+ k--;
169
+
178
170
  }
179
- }
171
+ }
180
172
  }
181
173
  }
182
174
  }