質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C

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

ネットワーク

ネットワークとは、複数のコンピューター間を接続する技術です。インターネットが最も主流なネットワークの形態で、TCP/IP・HTTP・DNSなどの様々なプロトコルや、ルータやサーバーなどの様々な機器の上に成り立っています。

Q&A

2回答

3732閲覧

C言語 ネットワークプログラミング selectの使い方

shogo812

総合スコア7

C

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

ネットワーク

ネットワークとは、複数のコンピューター間を接続する技術です。インターネットが最も主流なネットワークの形態で、TCP/IP・HTTP・DNSなどの様々なプロトコルや、ルータやサーバーなどの様々な機器の上に成り立っています。

0グッド

1クリップ

投稿2017/12/26 07:18

C言語プログラミング初心者です.
ネットワークプログラミングでわからないところがあり,また質問させていただきました.
前回質問したときよりも少し簡単なものを作ろうと思いました.
クライアントが一つに対し,複数のサーバがつながっているネットワークモデルでデータのやり取りを行いたいと考え,プログラミングしてみたのですが,selectの使い方が悪いのか上手く動作してくれません.
プログラムの内容としては複数のサーバーが同時に容量の大きいデータ(下記のコードでは160MB)を作成し,送信.クライアント側でselectを用いて受信し受信時間を計測.といった形で書いてみたつもりなのです.
しかし,サーバー1(172.168.0.2),サーバー2(172.168.0.3)を起動した後,クライアント(172.168.0.1)を起動するとサーバー2のパケットは受信できたのですが,サーバー1で送信は完了するのですが,クライアント側ではサーバ1のデータ受信の計測時間が出力されず,強制終了と出力されてしまいます.

サーバー側

C

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4#include <sys/types.h> 5#include <sys/socket.h> 6#include <netinet/in.h> 7#include <errno.h> 8 9 10typedef struct { 11 double deg; 12 double dist; 13}point; 14 15//ダミーのデータを詰める 16void makeData(int datanum,point *data){ 17 int i; 18 double col,val; 19 for(i=0;i<datanum;i++){ 20 21 col = (double)i; 22 data[i].deg = col; 23 24 val += 0.01; 25 data[i].dist = val; 26 } 27 28 printf("%f %f\n",col,val); 29} 30 31 32int main() 33{ 34 FILE *fpr; 35 int sock0; 36 struct sockaddr_in addr; 37 struct sockaddr_in client; 38 int len; 39 int sock; 40 int yes = 1; 41 42 const static int DATANUM = 10000000; 43 int i; 44 45 point *pbuf; 46 int res; 47 48 49 50 //ソケットOpen 51 sock0 = socket(AF_INET, SOCK_STREAM, 0); 52 addr.sin_family = AF_INET; 53 addr.sin_port = htons(11111); 54 addr.sin_addr.s_addr = INADDR_ANY; 55 setsockopt(sock0, SOL_SOCKET, SO_REUSEADDR, (const char *)&yes, sizeof(yes)); 56 bind(sock0, (struct sockaddr *)&addr, sizeof(addr)); 57 listen(sock0, 5); 58 len = sizeof(client); 59 sock = accept(sock0, (struct sockaddr *)&client, &len); 60 61 62 //point型の配列をDATNUMだけ確保。その中にデータを入れる。 63 pbuf = (point *)malloc(sizeof(point)*DATANUM); 64 makeData(DATANUM,pbuf); 65 66 /* サーバからデータを送信 */ 67 res = send(sock,pbuf,sizeof(point)*DATANUM,0); 68 printf( "%d bytes sent, %s\n",res, strerror( errno ) ); 69 70 close(sock); 71 close(sock0); 72 73 free(pbuf); 74 75 return 0; 76} 77

クライアント

C

1#include <stdio.h> 2#include <stdlib.h> 3#include <unistd.h> 4#include <sys/types.h> 5#include <sys/socket.h> 6#include <netinet/in.h> 7#include <string.h> 8#include <errno.h> 9#include <math.h> 10#include <time.h> 11 12 13typedef struct { 14 double deg; 15 double dist; 16}point; 17 18 19typedef struct { 20 int datanum; 21 point *meas; 22}frame; 23 24 25void recvFrame(frame *f,int sock); 26void recvFrame2(frame *f,int sock); 27 28void recvFrame(frame *f,int sock){ 29 int i; 30 int ret; 31 int bytenum; 32 int cur_pos = 0; 33 char *rbuf; 34 char *pbuf; 35 point p1; 36 struct timespec startTime, endTime; 37 38 printf("sizeof(point)=%d\n",sizeof(point)); 39 40 bytenum = f->datanum * sizeof(point); 41 printf("bytenum=%d\n",bytenum); 42 43 f->meas = (point *)malloc(bytenum); 44 rbuf = (char *)malloc(bytenum); 45 pbuf = (char *)malloc(bytenum); 46 47 48 clock_gettime(CLOCK_REALTIME, &startTime); 49 50 while(bytenum > cur_pos){ 51 52 ret = recv(sock,rbuf,bytenum,0); 53 54 memcpy(&(pbuf[cur_pos]),rbuf,ret); 55 56 cur_pos += ret; 57 } 58 59 memcpy(f->meas,pbuf,bytenum); 60 61 clock_gettime(CLOCK_REALTIME, &endTime); 62 63 //printf("START = %10ld.%09ld\n", startTime.tv_sec, startTime.tv_nsec); 64 //printf(" END = %10ld.%09ld\n", endTime.tv_sec, endTime.tv_nsec); 65 printf("SOCK1 TIME = "); 66 if(endTime.tv_nsec < startTime.tv_nsec){ 67 printf("%10ld.%09ld", endTime.tv_sec -startTime.tv_sec - 1, endTime.tv_nsec + 1000000000 - startTime.tv_nsec); 68 }else{ 69 printf("%10ld.%09ld",endTime.tv_sec - startTime.tv_sec, endTime.tv_nsec - startTime.tv_nsec); 70 } 71 printf("(sec)\n"); 72 73 free(pbuf); 74 free(rbuf); 75} 76 77void recvFrame2(frame *f,int sock){ 78 int i; 79 int ret; 80 int bytenum; 81 int cur_pos = 0; 82 char *rbuf; 83 char *pbuf; 84 point p1; 85 struct timespec startTime, endTime; 86 87 printf("sizeof(point)=%d\n",sizeof(point)); 88 89 bytenum = f->datanum * sizeof(point); 90 printf("bytenum=%d\n",bytenum); 91 92 f->meas = (point *)malloc(bytenum); 93 rbuf = (char *)malloc(bytenum); 94 pbuf = (char *)malloc(bytenum); 95 96 97 clock_gettime(CLOCK_REALTIME, &startTime); 98 99 while(bytenum > cur_pos){ 100 101 ret = recv(sock,rbuf,bytenum,0); 102 103 memcpy(&(pbuf[cur_pos]),rbuf,ret); 104 105 cur_pos += ret; 106 } 107 108 memcpy(f->meas,pbuf,bytenum); 109 110 clock_gettime(CLOCK_REALTIME, &endTime); 111 112 //printf("START = %10ld.%09ld\n", startTime.tv_sec, startTime.tv_nsec); 113 //printf(" END = %10ld.%09ld\n", endTime.tv_sec, endTime.tv_nsec); 114 printf("SOCK2 TIME = "); 115 if(endTime.tv_nsec < startTime.tv_nsec){ 116 printf("%10ld.%09ld", endTime.tv_sec -startTime.tv_sec - 1, endTime.tv_nsec + 1000000000 - startTime.tv_nsec); 117 }else{ 118 printf("%10ld.%09ld",endTime.tv_sec - startTime.tv_sec, endTime.tv_nsec - startTime.tv_nsec); 119 } 120 printf("(sec)\n"); 121 122 free(pbuf); 123 free(rbuf); 124} 125 126 127int main() 128{ 129 struct sockaddr_in server, server2; 130 int sock,sock2; 131 fd_set fds, readfds; 132 int maxfd; 133 int len, len2; 134 int n; 135 struct timeval tv; 136 137 sock = socket(AF_INET, SOCK_STREAM, 0); 138 sock2 = socket(AF_INET, SOCK_STREAM, 0); 139 140 server.sin_family = AF_INET; 141 server.sin_port = htons(11111); 142 server.sin_addr.s_addr = inet_addr("172.168.0.2"); 143 144 server2.sin_family = AF_INET; 145 server2.sin_port = htons(22222); 146 server2.sin_addr.s_addr = inet_addr("172.168.0.3"); 147 148 connect(sock, (struct sockaddr *)&server, sizeof(server)); 149 connect(sock2, (struct sockaddr *)&server2, sizeof(server2)); 150 151 FD_ZERO(&readfds); 152 153 FD_SET(sock, &readfds); 154 FD_SET(sock2, &readfds); 155 156 tv.tv_sec = 10; 157 tv.tv_usec = 0; 158 159 if(sock > sock2){ 160 maxfd = sock; 161 }else{ 162 maxfd = sock2; 163 } 164 165 frame f1,f2; 166 f1.datanum = 10000000; 167 f2.datanum = 10000000; 168 169 while (1) { 170 memcpy(&fds, &readfds, sizeof(fd_set)); 171 172 n = select(maxfd+1, &fds, NULL, NULL, &tv); 173 174 if(n==0){ 175 printf("timeout\n"); 176 break; 177 } 178 179 if(FD_ISSET(sock, &fds)){ 180 recvFrame(&f1,sock); 181 } 182 183 if(FD_ISSET(sock2, &fds)){ 184 recvFrame2(&f2,sock2); 185 } 186 187 } 188 189 close(sock); 190 close(sock2); 191 192 return 0; 193} 194

selectの使い方がまずいのでしょうか?
どなたかお力添えよろしくお願いします.

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

これは「1クライアント」が「複数のサーバー」に接続することを意図したプログラムのように思えます。そういうシステム設計が存在しないわけではありませんが、変則的ではあります。初心者ということならば、まずは一般的な形から試してみることなんじゃないでしょうか。select()の使い所を学ぶためであれば1対1通信でもできます。その場合でも、select()による待ち処理を持たせるのはサーバー側のプログラムでしょう。

投稿2017/12/27 09:09

編集2017/12/27 11:15
keicha_hrs

総合スコア6766

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

サーバーのコードを見ると送信が完了したらソケットをクローズしています。

fd_setの領域にはあくまで「通信中のファイルディスクリプターのみ」を設定すべきですが、ご質問のコードではそれを気にせずサーバー側がクローズ済みかも知れないファイルディスクリプターも含めて毎回readfdsに指定してしまってますね?

通信相手がソケットをクローズした場合もselectはそれを検知できます(EOFとして)。そのソケットでの通信が完了したことを検知したら速やかにcloseし、以降のselectではそのファイルディスクリプターをselectの対象外にすべきでしょう。そうしないとselectは期待通りの動作(監視対象のソケットがreadyになるまでプロセスをブロック)になってくれないと思います。


writefdsを省略する(NULL)のはよいですけど、エラーを検知できた方がより精密な処理が作れる気がするのでerrorfdsは省略しない方がよいかも知れません。エラーが起きた時それを検出しないでいるとselectはどうなるんでしょうか・・・-1が返ってくるからエラーが起きたことはわかるのでしょうが、「どのソケットで異常が発生したか」などは処理を書きにくい気がします。

投稿2017/12/26 09:20

KSwordOfHaste

総合スコア18392

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問