TCPでの非同期型select関数について

このQ&Aのポイント
  • マッキントッシュOS-X上で動くTCP通信プログラムを作る場合について教えてください。
  • ウィンドウ環境なので、アプリがフリーズしてしまわないために、以下のような非同期処理が考えられます。この場合、データが来ていなくても、while(1)がぐるぐる回るので無駄にプロセスを食ってしまうと思うのですが、これはしかたのないことでしょうか。もっとよい方法がるのでしょうか。
  • Winsockだとイベント応答関数での受信処理処理ができてエレガントなのですが、バークレイソケットでは、どうすべきなのか疑問に思い質問させていただきました。よろしくお願いします。
回答を見る
  • ベストアンサー

TCPでの非同期型select関数について

マッキントッシュOS-X上で動くTCP通信プログラムを作る場合について教えてください。 ウィンドウアプリを考えています。 ウィンドウ環境なので、アプリがフリーズしてしまわないために、 以下のような非同期処理が考えられます。 この場合、データが来ていなくても、while(1)がぐるぐる回るので 無駄にプロセスを食ってしまうと思うのですが、これはしかたのないことでしょうか。 もっとよい方法がるのでしょうか。 Winsockだとイベント応答関数での受信処理処理ができてエレガントなのですが、 バークレイソケットでは、どうすべきなのか疑問に思い質問させていただきました。 よろしくお願いします。 //ソケットを非同期モードにセット val = 1; ioctl(sock, FIONBIO, &val); while (1) {   memcpy(&fds, &readfds, sizeof(fd_set));   select(2, &fds, NULL, NULL, NULL);   // sockに読み込み可能データが届いている場合は、受信   if (FD_ISSET(sock, &fds)) {     memset(buf, 0, sizeof(buf));     recv(sock, buf, sizeof(buf), 0);   }   else{     //受信データがなかったときの処理   } }

質問者が選んだベストアンサー

  • ベストアンサー
  • hidebun
  • ベストアンサー率50% (92/181)
回答No.2

selectの第5引数にNULLを指定していますが、ソケットに変化がない場合、無期限に処理をブロックします。 もしかして、これを0秒に指定しようとしているということでしょうか。 もしそうであれば、すぐに関数を抜けて、ぐるぐると回りますね。 でも、タイムアウトの時間指定が、以下のように、マイクロ秒単位で、できるので struct timeval {  long tv_sec; /* 秒 */  long tv_usec; /* マイクロ秒 */ }; 多少でも待ちを入れれば、CPUリソースの消費は、抑えられるはずですが。 それが気になるようなら、データ受信専用のスレッドとUIスレッドを分けましょう。

ycuhakecha
質問者

お礼

ありがとうございました。 まさに、selectのタイムアウトをゼロの場合を聞こうとして おかしな質問になっていることに気づきました。 別スレッドにする。。。なるほど、エレガントです。 あらためて、 winsockのイベント応答関数はよくできていると思いました。

その他の回答 (1)

  • hidebun
  • ベストアンサー率50% (92/181)
回答No.1

> データが来ていなくても、while(1)がぐるぐる回るので > 無駄にプロセスを食ってしまうと思うのですが、これはしかたのないことでしょうか。 selectは、登録したソケットをブロッキングで監視し、無駄なCPUリソースを消費しない状態でデータの到着を待ちます。データを受信すると、selectより下の行を実行します。 なので、無駄にCPU資源を使用することはありません。

ycuhakecha
質問者

お礼

ありがとうございました。 selectのタイムアウトをゼロの場合を聞こうとして おかしな質問になっていることに気づきました。

関連するQ&A

  • 多人数のチャットソフトを考えています

    winsockを使ってプログラミングしています。 1対1のチャットはできたのですが、サーバを挟んで1対多のチャットがうまくいきません。 サーバがクライアントごとにスレットを作って、acceptするたびにできるディスクリプタを配列に格納して、それを元に送信してきたクライアント以外に送るということをしたいと思っています。 説明下手ですいません。。。。 サーバ↓↓↓ ・・・・・・・・・初期化は略・・・・・・・・・・・・・・・・・・・・ while(1){ Csock[i] = accept(s,(struct sockaddr *) &Saddr, &Ssize); CreateThread(Csock[i]);  //クライアントごとにスレッドを作ってるつもり i++; } /**CreateThreadで作るスレッド**********/ unsigned __stdcall recvthread(void *lpx) //lpxにはクライアントのディスクリプタを格納 { fd_set fds, readfds; int sock = *(int *)lpx; int recvSize; char recvbuf[256]; FD_ZERO(&readfds); FD_SET(sock, &readfds); while(1) { memcpy(&fds, &readfds, sizeof(fd_set)); memset(recvbuf, 0, sizeof(recvbuf)); select(0, &fds, NULL, NULL, NULL); if (FD_ISSET(sock, &fds)) { WaitForSingleObject(mutex, INFINITE); recvSize = recv(sock, recvbuf, sizeof(recvbuf), 0); Send(sock,(const char)recvbuf); ReleaseMutex(mutex); if(recvSize == 0) { printf("通信終了\n"); closesocket(sock); break; } if(recvSize == -1) { printf("socket errer (recv)\n"); closesocket(sock); break; } } } return 0; } void Send(int sock,char recvbuf) { for(int j=0;j<5;j++) { if(Csock[j]==sock) continue; send(Csock[j],(const char*)recvbuf,sizeof(recvbuf),0); } } これを実行するとスレッドが無数に作成され、強制終了させられてしまいます。 初級者なのでプログラムのミスがあったら教えて下さい。 違うアイディアもあったら教えて欲しいです。見にくいと思いますがよろしくお願いします。。。。

  • c言語のチャットプログラムのsendとrecv

    現在、複数のクライアントからサーバーにメッセージを送りサーバーからクライアントにメッセージを送るというものを作成しているのですが、クライアントからサーバーにはメッセージを送れるのですが、サーバー側からクライアント1人にしか送れず、クライアント全員にメッセージを送信できませんので、よろしければアドバイスをお願いします サーバーのプログラム インクルード省略 #define BUF_LEN 256 typedef struct CLIENT_INFO { char hostname[BUF_LEN]; char ipaddr[BUF_LEN]; int port; time_t last_access; } CLIENT_INFO; CLIENT_INFO client_info[FD_SETSIZE]; int listening_socket; struct sockaddr_in sn; int accept_new_client(int sock){ int len; int new_socket; struct hostent *peer_host; struct sockaddr_in peer_sin; len = sizeof(sn); new_socket = accept(listening_socket, (struct sockaddr *)&sn, &len); if ( new_socket == -1 ){ perror("accept"); exit(1); } if ( new_socket > FD_SETSIZE-1 ){ return -1; } len = sizeof(peer_sin); getpeername(new_socket, (struct sockaddr *)&peer_sin, &len); peer_host = gethostbyaddr((char *)&peer_sin.sin_addr.s_addr, sizeof(peer_sin.sin_addr), AF_INET); strncpy(client_info[new_socket].hostname, peer_host->h_name, sizeof client_info[new_socket].hostname); strncpy(client_info[new_socket].ipaddr, inet_ntoa(peer_sin.sin_addr), sizeof client_info[new_socket].ipaddr); client_info[new_socket].port = ntohs(peer_sin.sin_port); time(&client_info[new_socket].last_access); printf("接続: %s (%s) ポート %d ディスクリプタ %d 番\n", client_info[new_socket].hostname, client_info[new_socket].ipaddr, client_info[new_socket].port, new_socket); return new_socket; } int read_and_reply(int sock){ int read_size; char buf[BUF_LEN]; read_size = read(sock, buf, sizeof(buf)-1); if ( read_size == 0 || read_size == -1 ){ printf("%s (%s) ポート %d ディスクリプタ %d 番からの接続が切れました。\n", client_info[sock].hostname, client_info[sock].ipaddr, client_info[sock].port, sock); close(sock); client_info[sock].last_access = 0; } else { buf[read_size] = '\0'; printf("%s (%s) ポート %d ディスクリプタ %d 番からのメッセージ: %s", client_info[sock].hostname, client_info[sock].ipaddr, client_info[sock].port, sock, buf); write(sock, buf, strlen(buf)); time(&client_info[sock].last_access); } return read_size; } int main(){ fd_set target_fds; fd_set org_target_fds; int sock_optval = 1; int port = 5000;    listening_socket = socket(AF_INET, SOCK_STREAM, 0); if ( setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, &sock_optval, sizeof(sock_optval)) == -1 ){ perror("setsockopt"); exit(1); }  sn.sin_family = AF_INET; sn.sin_port = htons(port); sn.sin_addr.s_addr = htonl(INADDR_ANY); if ( bind(listening_socket, (struct sockaddr *)&sn, sizeof(sn)) < 0 ){ perror("bind"); exit(1); }   if ( listen(listening_socket, SOMAXCONN) == -1 ){ perror("listen"); exit(1); printf("ポート %d を見張ります。\n", port);   FD_ZERO(&org_target_fds); FD_SET(listening_socket, &org_target_fds);   while (1){ int i; time_t now_time; struct timeval waitval; waitval.tv_sec = 2; waitval.tv_usec = 500;  memcpy(&target_fds, &org_target_fds, sizeof(org_target_fds));  select(FD_SETSIZE, &target_fds, NULL, NULL, &waitval);  for ( i=0 ; i<FD_SETSIZE ; i++ ) { if ( FD_ISSET(i, &target_fds) ) { printf("ディスクリプタ %d 番が読み込み可能です。\n", i); if ( i == listening_socket ) { int new_sock; new_sock = accept_new_client(i); if ( new_sock != -1 ) { FD_SET(new_sock, &org_target_fds); } } else {int read_size;  read_size = read_size; read_size = read_and_reply(i); if ( read_size == -1 || read_size == 0 ) { FD_CLR(i, &org_target_fds); } } } } time(&now_time); for ( i=0 ; i<FD_SETSIZE ; i++){ if ( ! FD_ISSET(i, &org_target_fds) ) continue; if ( i == listening_socket ) continue; if ( now_time-60 > client_info[i].last_access ) { close(i); FD_CLR(i, &org_target_fds); } } } close(listening_socket); FD_CLR(i, &org_target_fds); } }

  • recv関数でフリーズしてしまう

    現在Winsockを用いた簡単なパケット送受信のソフトを作成しています。 開発環境はVisual Studio2008で、ダイアログベースで作成しています。 パケットの受信側の処理なんですが、いつパケットが来てもいいように、 Ontimerで、定期的に受信処理をしようと思っています。 そこでOntimer内に以下のようにプログラムしたところ、コンパイルエラー はないものの、数秒経つと応答なしとなりフリーズしてしまいます。 原因を探ったところrecv関数が原因で、recv関数をコメントアウトした ところ、フリーズはしなくなりました。また、エラー処理は省略していま すが、ソケットの作成失敗などはありませんでした。 なぜrecv関数でフリーズが起きてしまうのか、原因が分かる方は いらっしゃいますか? OnTimer(UINT nIDEvent){ WSAData wsaData; SOCKET sock; struct sockaddr_in addr; char buf[2048]; WSAStartup(MAKEWORD(2,0), &wsaData); sock = socket(AF_INET, SOCK_DGRAM, 0); addr.sin_family = AF_INET; addr.sin_port = htons(12345); addr.sin_addr.S_un.S_addr = INADDR_ANY; bind(sock, (struct sockaddr *)&addr, sizeof(addr)); memset(buf, 0, sizeof(buf)); recv(sock, buf, sizeof(buf), 0); closesocket(sock); WSACleanup(); }

  • TCP/IP通信型電話番号検索プログラムを作りたいです。

    TCP/IP通信型電話番号検索プログラムを作りたいです。 クライアントは以下のようで大丈夫みたいなのですが、サーバの方を修正しなければなりません。 この質問で「TCP/IP通信型大文字・小文字変換プログラム」を発見しました。 サーバー側プログラム #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <unistd.h> #include <sys/socket.h> #include <arpa/inet.h> #define SOCK_NAME "./socket" int main() { int i; int fd1, fd2; struct sockaddr_in saddr; struct sockaddr_in caddr; int len; int ret; char buf[1024]; if((fd1 =socket(AF_INET, SOCK_STREAM, 0)) < 0 ){ perror("socket"); exit(1); } memset((char *)&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; saddr.sin_addr.s_addr=INADDR_ANY; saddr.sin_port=htons(1357); unlink(SOCK_NAME); if(bind(fd1, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { perror("bind"); exit(1); } if(listen(fd1,5) < 0 ) { perror("listen"); exit(1); } while(1){ len = sizeof(caddr); if((fd2 = accept(fd1, (struct sockaddr *)&caddr, &len)) < 0){ perror("accept"); exit(1); } fprintf(stderr, "Connection established: socket %d used.\n", fd2); while((ret = read(fd2, buf, 1024)) > 0 ){ fprintf(stderr, "read: &s\n", buf); for(i=0; i<ret; i++) if(islower(buf[i])) buf[i] = toupper(buf[i]); if(isupper(buf[i])) buf[i] = tolower(buf[i]); fprintf(stderr, "write: %s\n", buf); write(fd2, buf, 1024); } close(fd2); } close(fd1); return 0; } 先生によると、クライアントは同じもので良いそうです。 誰か、助けて下さい。

  • send-recvで複数データの送受信

    初歩的な質問で恐縮ですがよろしくお願いいたします。 send側 :WindowsVista VC6 recv側 :Linux2.6.18-at9 Debian PowerPC でunsigned longのデータ数千個を順次送受信するプログラムを組んでいるのですが不調です。 ともにBlockingモードで動作しているのだから双方にWhileループを組めば特段のHandShakeは不要で受信側所定バッファに逐次取り込めるのだと思っていました。しかし: 1.受信側ループにprintf、sleep(1)等を入れないと受からない。  なお受信側はMainとは別のスレッドにしています。 2.毎回内容ゼロのデータがもう一つ加わってしまう。  recvが毎回データ到着までBlockつまり待ちにしていると期待したのですが、2回通り抜けたような効果があり、各データにゼロデータがもう一行付加されてしまう。つまりデータ量が2倍になる。 プログラム: 送信側: SOCKET s; unsigned long dataBuf char buf[20]; int ok; while ( count < DATANO) ){  fread(&dataBuf, sizeof(dataBuf),1,fp);      // ファイルより読込み sprintf(buf, "%d", dataBuf); ok = send(s, buf, sizeof(buf), 0); // Blocking Mode ? if(ok==SOCKET_ERROR){ printf("Command送信不良"); exit(1); } count++; } 受信側: void* dataReceiveThread(void* pParam) {  char buf[10];  int recvSize, count = 0;  unsigned long val, memBuf[4096];  while(1){   memset(buf, 0, sizeof(buf));   recvSize = recv(conn_fd, buf, sizeof(buf), 0); // Blocking Mode   if(recvSize == 0){    printf("conn_fd broken by Host\n");    close(conn_fd);    break;   }   else if (recvSize == -1) {    perror("recv");    exit(EXIT_FAILURE);   } val = atol(buf); ⇒ printf("val %x\n", val);   if (count < DATANO){ memBuf[count] = val; else break; count++; } このプログラムは初回のデータは問題なく受信できます。 以降のデータは⇒でループ速度を下げないと受信できません。しかしこれは仕様に合いません。 ただしデータ量が2倍になってしまうのでFlipFlopを入れてループを間引いて強引に辻褄合わせをしたところデータはそれらしく受信できます。しかし指定回数ループできません。 recvのBlock機能を誤解しているのかもしれない考え、selectを入れるなどしたのですが解決しません。send-recvの基本仕様を理解していないためと思われます。 ご教示願えれば幸いです。

  • 非同期関数とノンブロッキング関数について(winsock)

    こんばんわ。 VC++.NETにてコンソール上でソケットプログラミングをしています。 非同期モードとノンブロッキング関数について知りたいのですが、私は、今までTCPやUDPでsendtoやsend関数を使用してきました。しかし、非同期やノンブロッキング関数があることを知り、詳しく知りたいと思っています。 1.非同期やノンブロッキング関数はGUI作成を行う上では重要であるが、コンソール上でプログラミングを行っている場合は利用しなくてよいのでしょうか? 2.以下のWSAAsyncSelect関数の第2引数の設定がわかりません。サンプルでは、hwndに関連付けられたウィンドウがSM_EVENTメッセージを受け取りますと記述されていますが、ウィンドウを利用していないコンソールアプリでの記述方法はありますでしょうか? HWND hwnd; WSAAsyncSelect(Sock,hwnd,SM_EVENT,FD_WRITE); と記述し実行した場合、強制終了されてしまいます。 3.たとえば、送信側から送信したパケットを受信側で受信し、再度受信側から送信側へ送信する場合を考えると、 送信側で送信と受信が必要です。この場合、マルチスレッド処理が必要だと思うのですが、非同期のFD_WRITEとFD_READを使うことで、シングルスレッドで実現可能でしょうか? よろしくお願い致します。

  • TCP/IP通信型大文字・小文字変換プログラム

    TCP/IP通信型大文字・小文字変換プログラムを作りたいです。 しかし、うまく2つのプログラムが接続されません。 恐らく、IPアドレスやホスト名の問題だと思います。 超初心者でそこのところをあまり理解していません。 どなたかプログラムの補足をお願いします。 概要は ・クライアント キーボードから文字列を入力し、サーバーに送信。 サーバーから送信された文字列を画面に出力。 ・サーバー クライアントから送信された文字列に対し、 大文字は小文字に、小文字は大文字に変換して返す。 クライアント側プログラム #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #define SOCK_NAME "./socket" int main() { struct sockaddr_in saddr; int soc; char buf[1024]; if ( (soc =socket(AF_INET, SOCK_STREAM, 0 ) ) < 0 ) { perror("socket"); exit(1); } memset((char *)&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; saddr.sin_addr.s_addr=inet_addr("192.168.1.1"); saddr.sin_port=htons(1357); if(connect(soc, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { perror("connect"); exit(1); } fprintf(stderr, "Connection established: socket %d used.\n", soc); while(fgets(buf, 1024, stdin)){ if(buf[strlen(buf) -1] == "\n") buf[strlen(buf) -1] = "\0"; write(soc, buf, 1024); read(soc, buf, 1024); fprintf(stdout, "%s\n", buf); } close(soc); return 0; } サーバー側プログラム #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <unistd.h> #include <sys/socket.h> #include <arpa/inet.h> #define SOCK_NAME "./socket" int main() { int i; int fd1, fd2; struct sockaddr_in saddr; struct sockaddr_in caddr; int len; int ret; char buf[1024]; if((fd1 =socket(AF_INET, SOCK_STREAM, 0)) < 0 ){ perror("socket"); exit(1); } memset((char *)&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; saddr.sin_addr.s_addr=INADDR_ANY; saddr.sin_port=htons(1357); unlink(SOCK_NAME); if(bind(fd1, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { perror("bind"); exit(1); } if(listen(fd1,5) < 0 ) { perror("listen"); exit(1); } while(1){ len = sizeof(caddr); if((fd2 = accept(fd1, (struct sockaddr *)&caddr, &len)) < 0){ perror("accept"); exit(1); } fprintf(stderr, "Connection established: socket %d used.\n", fd2); while((ret = read(fd2, buf, 1024)) > 0 ){ fprintf(stderr, "read: &s\n", buf); for(i=0; i<ret; i++) if(islower(buf[i])) buf[i] = toupper(buf[i]); if(isupper(buf[i])) buf[i] = tolower(buf[i]); fprintf(stderr, "write: %s\n", buf); write(fd2, buf, 1024); } close(fd2); } close(fd1); return 0; }

  • selectを使った文がうまくいきません

    C言語でselectを使ってチャットサーバを実現したいのですが、うまくいきません。 以下にメッセージの受信と新しいクライアントの受付を処理するループのコードを示します。 以下のコードのif(select(FD_SETSIZE,&rfds,NULL,NULL,&tv)>0) { ... } の分岐に入って1回目の処理を行った後、以降のループでメッセージを送ってもこの分岐に入らなくなります。 どなたか原因がわかるかたよろしくお願いします。 while(1){ FD_ZERO(&rfds); /* rfds を空集合に初期化*/ FD_SET(sock,&rfds); /* 接続要求を待つソケット*/ /* クライアントを受け付けたソケット*/ /* 監視する待ち時間を1 秒に設定*/ tv.tv_sec = 1; tv.tv_usec = 0; /* 標準入力とソケットからの受信を同時に監視する*/ max = sock; for(i = 0;i = k ; i++){ if(max > csock[i]){ max = csock[i]; } } if(select(FD_SETSIZE,&rfds,NULL,NULL,&tv)>0) { /* s3 */ if(FD_ISSET(sock,&rfds)){ /* s4 */ /* クライアントの受付*/ clen = sizeof(clt); if ( ( csock[k] = accept(sock,(struct sockaddr *)&clt,&clen) ) <0 ) { perror("accept"); exit(2); } FD_SET(csock[k],&rfds); if(k < MAXCLIENTS){ strcpy(jusin,"REQUEST ACCEPTED\n"); write(csock[k],jusin,strlen(jusin)); /* s5 */ read(csock[k],nbuf,sizeof(nbuf)); check = 0; for(i = 0;i < 5;i++){ for(j = 0; j < 100;j++){ if(name[i][j] != nbuf[j]){ check = 1; break; } if(nbuf[j] == '\n'){ break; } } } if(check != 1){ strcpy(userkyohi,"USERNAME REJECTED\n"); write(csock[k],userkyohi,strlen(userkyohi)); write(csock[k],nbuf,strlen(nbuf)); close(csock[k]); } else{ i = 0; while(rbuf[i] != '\n'){ name[k][i] = nbuf[i]; i++; } name[k][i]= '\n'; strcpy(toroku,"USERNAME REGISTERED\n"); write(csock[k],toroku,sizeof(toroku)); k++; } }else{ strcpy(kyohi,"REQUEST REJECTED\n"); write(csock[k],kyohi,strlen(kyohi)); close(csock[k]); } } for(i = 0;i < k;i++){ if(FD_ISSET(csock[i],&rfds)){ read(csock[i],mbuf,sizeof(mbuf)); if(mbuf[0] == 'E'&& mbuf[1]=='O' && mbuf[2] == 'F'){ /* s7 */ for(;i == k ; i++){ csock[i]=csock[i+1]; memset(name[i],0,sizeof(name[i])); j = 0; while(name[i+1][j] != '\n'){ name[i][j] = name[i+1][j]; } } close(csock[k]); k--; } else{ memset(msg, 0, sizeof(msg)); j = 0; while(name[i][j] != '\n'){ msg[j] = name[i][j]; j++; } msg[j] = ' ';j++; msg[j] = '>';j++; l = 0; while(mbuf[l]!='\0'){ msg[j]= mbuf[l]; j++; l++; } msg[j] = '\0'; for(t = 0; t < k;t++){ write(csock[t],msg,sizeof(msg)); } } } } } }

  • パケット受信 recvfrom( )について

    お世話になります。 WinSockを用いてUDPパケット受信プログラムを作成しています。 環境はVC++です。ダイアログベースで、 STARTボタンを押すと受信開始します。 送信側よりパケットを1000個送信した場合、受信側では、 int num; SOCKET sock; char buf[1500]; //ソケットの設定は省略 while(1){ num = recvfrom(sock, buf, sizeof(buf), 0, NULL, NULL);  printf("%d",num ); if( num == SOCKET_ERROR){ break; } } recvfrom()で受信していますが、送信側で送信が完了しても while()を抜けないのか、応答なし(フリーズ)してしまいます。 printf()で表示してみると、 ちゃんと送信パケット個数回表示されています。 送信パケット数は変動するため、受信側のプログラムには 個数がわかりませんため、while()でループしています。 while()を抜ける条件はどうしたらいいのでしょうか? ちなみにrecvfrom()の戻り値として SOCKET_ERROR,0を指定してもエラーになります。 長くなりましたが、どうぞよろしくお願い致します。

  • recvfrom関数の戻り値がおかしいんですが…

    初めて投稿させていただきます。 現在、Cにてあるクライアントプログラムを作成している者です。 構成は以下の通り。 《構成》 サーバ:PLC(シーケンサと書けば大体の方はわかりますか?) クライアント:Linux Ubuntu9.10 通信方式:TCP/IP 《開発環境》 言語:C IDE:eclipse コンパイラ:gcc 4.x 《質問》 クライアントプログラムからASCIIデータをサーバへ送信し、サーバはクライアントから受信したASCIIデータに応答し、ASCIIデータ伝文を返信してきます。 このサーバからのASCIIデータ応答伝文をrecvfrom関数で受信し、応答伝文のASCIIデータを'buf'変数に格納し、標準出力関数で表示させるといったプログラムです。 このプログラムでは、ユーザ関数内でrecvfrom関数をコールしているのですが、ユーザ関数内でrecvfrom関数をコールした場合、受信データの先頭4byteしか受信できておらず、困っています。 ちなみに、main関数内でrecvfrom関数をコールすると、応答伝文全体のデータをきちんと受信できています。 ちなみに、サーバの応答ASCIIデータ伝文は、仕様通り(期待通り)のデータが返信されています。(ネットワークモニタ:wiresharkで確認済み) recvfrom関数をコールする場所によって、変数に格納するデータ量が変わるといったことがあるのでしょうか。 ソースの一部を添付します。 参照の上、アドバイス等いただけないでしょうか。 《ソース》 ◆mainソース #include ... :<-#include定義 int main{   :<-変数定義、変数初期値代入処理等 ユーザ関数1()コール<-ユーザ関数1内でソケット通信処理を動作させている。 ユーザ関数2()コール<-同上 } ◆ユーザ関数用ソース #include...   :<-#include定義 unsigned char ユーザ関数名1;<-ユーザ関数プロトタイプ宣言 unsigned char ユーザ関数名2:<-同上 char 変数1[5]; char s_buf[4096]; char buf[4096]; /*データ受信用バッファ*/ char 変数2[256]; size_t len; long l; int sock_fd; /*ソケット用ファイル記述子*/ struct sockaddr_in cl_addr; /*CPU用ソケットアドレス*/ socklen_t cl_len = 0; /*cl_addrのサイズ格納用*/ ssize_t n = 0; unsigned char ユーザ関数1(char *引数1,…char *引数5){   :送信データ生成処理 //* ソケット作成 *// if ((sock_fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { perror("socket"); return 1;   } //* 接続先定義*// memset(&cl_addr, 0, sizeof cl_addr); cl_addr.sin_family  = AF_INET; /*プロトコル定義*/ cl_addr.sin_addr.s_addr = inet_addr("***.***.***.***"); /*IPアドレス定義*/ cl_addr.sin_port  = htons(****); /*Port定義*/ //* 接続 *// if (connect(sock_fd, (struct sockaddr *)&cl_addr, sizeof cl_addr) < 0) { perror("connect"); return 1;   } //* データ送信 *// if(send(sock_fd, s_buf, strlen(s_buf), 0) < 0){ fprintf(stderr, "could not send message : %s\n", s_buf); exit(EXIT_FAILURE); } printf("\nSendMessage\n%s\n",s_buf); //* データ受信 *// cl_len = sizeof cl_addr; //*↓↓このrecvfrom関数でbuf内にサーバ応答伝文の先頭4byteのみが格納されている。↓↓*// if (( n = recvfrom(sock_fd, buf, sizeof buf,0, (struct sockaddr *)&cl_addr, &cl_len)) < 0) { perror("recvfrom"); return 1; } fprintf(stderr ,"TCP from addr = %s, port = %d\n", inet_ntoa(cl_addr.sin_addr), ntohs(cl_addr.sin_port) );

専門家に質問してみよう