複数クライアント接続
###問題
ユーザー名の登録などがうまく行かないです。空白文字で区切ったりしてはいるのですが。 また、クライアントがEOFを入力したら、そのユーザーのみのソケットを閉じて入力、受付待ちに戻るはずなのですが、ユーザー名を大量に出力して作業が強制的に終了してしまいます。
schat.c(サーバプログラム)
c
1#include <sys/types.h> 2#include <sys/socket.h> 3#include <sys/time.h> 4#include <sys/wait.h> 5#include <netinet/in.h> 6#include <netdb.h> 7#include <unistd.h> 8#include <sys/wait.h> 9#include <string.h> 10#include <stdio.h> 11#include <stdlib.h> 12#define BUFSIZE 256 13#define TIMEOUT 10 14#define MAXCLIENTS 5 15void myalarm(int sec); 16void timeout(); 17int main(int argc,char **argv) 18{ 19 int sock,h=0,k=5,csock[5];/*クライアントを受け付けたソケット*/ 20 struct sockaddr_in clt; 21 struct sockaddr_in svr; 22 struct hostent *cp; 23 int clen,nbytes,fdmax,flag; 24 int Nbyte[5]; 25 char USERNAME[5][32],Nbuf[32]; 26 fd_set rfds;/* select()で用いるファイル記述子集合*/ 27 struct timeval tv; 28 char rbuf[128],buffer[128],*arg; 29 memset(rbuf, 0, sizeof(rbuf)); 30 for ( int i = 0; i <k; i++ ){ 31 csock[i] = -1;//通信用の配列の初期化 32 } 33 /* select()が返ってくるまでの待ち時間を指定する変数*/ 34 35 if ((sock=socket(AF_INET,SOCK_STREAM,0))<0) { 36 perror("socket"); 37 exit(1); 38 } 39 /*クライアントからの接続待ち受けなど*/ 40 bzero(&svr,sizeof(svr)); 41 svr.sin_family=AF_INET; 42 svr.sin_addr.s_addr=htonl(INADDR_ANY); 43 svr.sin_port=htons(10140); 44 if(bind(sock,(struct sockaddr *)&svr,sizeof(svr))<0) { 45 perror("bind"); 46 exit(1); 47 } 48 if (listen(sock,5)<0) { 49 /*待ち受け数に5を指定*/ 50 perror("listen"); 51 exit(1); 52 } 53 while(1){ 54 FD_ZERO(&rfds); 55 FD_SET(sock,&rfds); 56 fdmax=sock; 57 for(int i=0;i<MAXCLIENTS;i++){ 58 if(csock[i]>0){ 59 if(csock[i]>fdmax){ 60 fdmax=csock[i]; 61 } 62 FD_SET(csock[i],&rfds); 63 } 64 } 65 tv.tv_sec = 1; 66 tv.tv_usec = 0;/*標準入力とソケットからの受信を同時に監視する*/ 67 section3: 68 if(select(fdmax+1,&rfds,NULL,NULL,&tv)>0){ 69 if(FD_ISSET(sock,&rfds)){ 70 for(int i=0;i<MAXCLIENTS;i++){ 71 clen=sizeof(clt); 72 if ( ( csock[i] = accept(sock,(struct sockaddr *)&clt,&clen) ) <0 ) { 73 perror("accept"); 74 exit(2); 75 } 76 if(sock<MAXCLIENTS){ 77 write(csock[i],"REQUEST ACCEPTED\n",17); 78 nbytes=read(csock[i],rbuf,sizeof(rbuf)); 79 strncpy(Nbuf,rbuf,nbytes-1); 80 Nbyte[i]=nbytes; 81 flag=0; 82 for(int j=0;j<MAXCLIENTS;j++){ 83 if(strcat(USERNAME[j],Nbuf)==0){ 84 flag=1; 85 char name[32]="REJECTED"; 86 write(csock[i],"USERNAME REJECTED\n",18); 87 strcat(name,Nbuf); 88 for(int k=0;k<MAXCLIENTS;k++) 89 write(csock[k],name,sizeof(name)); 90 close(csock[i]); 91 goto section3; 92 } 93 } 94 if(flag==0){ 95 write(csock[i],"USERNAME REGISTERED\n",20); 96 strncpy(USERNAME[i],Nbuf,Nbyte[i]-1); 97 char nll[]="\0"; 98 strcat(USERNAME[i],nll); 99 write(1,USERNAME[i],sizeof(USERNAME[i])); 100 k++; 101 goto section3; 102 } 103 104 105 } 106 } 107 } 108 for(int i=0;i<MAXCLIENTS;i++){ 109 if(FD_ISSET(csock[i],&rfds)){ 110 if(read(csock[i],rbuf,sizeof(rbuf))!=0){ 111 char STRING[64]="<"; 112 strcat(STRING,USERNAME[i]); 113 strcat(STRING,"\0"); 114 strcat(STRING,">"); 115 strcat(STRING,rbuf); 116 for(int j=0;j<MAXCLIENTS;j++){ 117 write(csock[j],STRING,sizeof(STRING)); 118 } 119 }else{ 120 fprintf(stderr,"01\n"); 121 close(csock[i]); 122 for(int j=0;MAXCLIENTS;j++){ 123 write(csock[j],USERNAME[i],sizeof(USERNAME[i])); 124 } 125 USERNAME[i][0]='\0'; 126 k--; 127 128 } 129 } 130 } 131 } 132 } 133 close(sock); 134 exit(0); 135}
socketの返り値は確認していますか?0から連番で返ってくることを想定しているようですけど、実際にそうなっていますか?
あれから大幅に進展したので、ソースコードを大幅に書き換えました。
状態遷移が決まっているのでしたら, それに合わせて関数化したほうが見通しが良くなります.
見通しが良くなると, それだけでバグが減る可能性が減ると期待できます.
main関数のなかでいろいろやりすぎです。
いくつかの関数にわけて処理するようにしてはいかがでしょうか。
クライアントから接続待ちとクライアントからの電文の受信待ちとを同じ個所で待っていますが、
これは必ずそうしなさいということなのでしょうか。
私としては
①クライアントからの接続待ち及びその対応処理
②クライアントからの電文の受信待ち及びその対応処理
に分け、上記の①②をずっと繰り返すほうが、処理が簡単になるような気がします。
①②は同じ箇所で行う仕様です。
回答2件
あなたの回答
tips
プレビュー