accept関数を使ったタイムアウト処理がうまくいかない

このQ&Aのポイント
  • C言語でソケット通信でサーバ側のaccept処理のブロック状態をalarm関数で事前にタイムアウトする秒数を設定しておき、割り込みをおこさせて割り込み処理後、再開した際にaccept関数がエラーを返しerrnoにEINTRが返ってきているかを判断してタイムアウト処理を行うという目的で以下のソースを作成しました。
  • しかし、実際に動作させてみるとalarmが呼び出されシグナルハンドラとして設定しているsigcatch関数が呼び出され、標準出力にsigcatch関数中で出力しているメッセージが出力されますが、そのままブロック状態から変化しませんでした。
  • ソケットのクライアントプログラムを接続したところ、acceptが成功して接続が確立されました。
回答を見る
  • ベストアンサー

acceptをalarmでタイムアウトさせる処理がうまくいきません

お世話になります。 C言語でソケット通信でサーバ側のaccept処理のブロック状態を alarm関数で事前にタイムアウトする秒数を設定しておき、割り込みをおこさせて割り込み処理後、再開した際にaccept関数がエラーを返しerrnoにEINTRが返ってきているかを判断してタイムアウト処理を行うという目的で以下のソースを作成しました。 しかし、実際に動作させてみるとalarmが呼び出されシグナルハンドラとして設定しているsigcatch関数が呼び出され、標準出力にsigcatch関数中で出力しているメッセージが出力されますが、そのままブロック状態から変化しませんでした。 ソケットのクライアントプログラムを接続したところ、acceptが成功して接続が確立されました。 この方式による実現が可能かどうか、不可能であれば代替方法を教えていただきたいと考えております。 お手数おかけしますが、ご回答のほどよろしくお願いします。 コンパイルおよび実行環境は以下となっています。 Red Hat Enterprise Linux ES release 4 (Nahant Update 3) Kernel 2.6.9-34.ELsmp on an i686 glibc-2.3.4-2.19 ###################以下、C言語のソースです##################### #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <signal.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <stdlib.h> #define BUFFER_SIZE 256 void sigcatch(int); int main() { unsigned short port = 9876; int srcSocket; int dstSocket; struct sigaction sa_sigint; struct sockaddr_in srcAddr; struct sockaddr_in dstAddr; int dstAddrSize = sizeof(dstAddr); int numrcv; char buffer[BUFFER_SIZE]; int status = 0; int select_cnt = 0; fd_set readfds; int n; struct timeval timeout; int re; char *toSendText = "This is a test"; memset(&srcAddr, 0, sizeof(srcAddr)); srcAddr.sin_port = htons(port); srcAddr.sin_family = AF_INET; srcAddr.sin_addr.s_addr = htonl(INADDR_ANY); srcSocket = socket(AF_INET, SOCK_STREAM, 0); bind(srcSocket, (struct sockaddr *) &srcAddr, sizeof(srcAddr)); listen(srcSocket, 1); printf("Waiting for connection ...\n"); memset(&sa_sigint, 0, sizeof(sa_sigint)); sa_sigint.sa_handler = sigcatch; sa_sigint.sa_flags = SA_RESTART; if (sigaction(SIGALRM, &sa_sigint, NULL) < 0) { perror("sigaction"); exit(1); } alarm(10); dstSocket = accept(srcSocket, (struct sockaddr *) &dstAddr, &dstAddrSize); if ( dstSocket == -1 ){ if ( errno == EINTR ){ printf("accept timeout!\n"); }else{ printf("accept error![%d]\n",errno); } exit(-1); } signal( SIGALRM , SIG_IGN ); printf("Connected from %s\n", inet_ntoa(dstAddr.sin_addr)); while(1) { FD_ZERO( &readfds ); FD_SET( dstSocket , &readfds ); n = dstSocket + 1; timeout.tv_sec = 0; timeout.tv_usec = 0; re = select( n , &readfds , NULL , NULL , &timeout ); select_cnt++; if( re > 0 ){ printf("select count %d\n",select_cnt); if ( FD_ISSET( dstSocket , &readfds ) ){ numrcv = recv(dstSocket, buffer, BUFFER_SIZE, 0); if(numrcv == 0 || numrcv == -1) { status = close(dstSocket); break; } printf("received: %s\n", buffer); send(dstSocket, toSendText, strlen(toSendText)+1, 0); } } } } void sigcatch(int sig) { printf("catch signal %d\n", sig); if (sig == SIGALRM) { printf("catch SIGALRM and exit.\n"); } }

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

  • ベストアンサー
  • tatsu99
  • ベストアンサー率52% (391/751)
回答No.3

要はacceptするときに、タイムアウトの監視もしたいということでしょうか。その場合は、alarmによる方法は採りません。 通常は、以下の方法を採ります。 acceptの前に、そのソケットに対し、selectを行います。その時、タイムアウト時間も指定します。selectから返るのは、acceptが出来る状態になったときか、selectがタイムアウトした場合の何れかです。

IamMasaki
質問者

お礼

行いたかったことはaccept時にタイムアウト監視をしたいということでした。 さっそくtatsu99さんの方法にて確認したところ無事タイムアウト監視ができるようになりました。ありがとうございます。 以下に修正ソースを記載します。 ###################以下、C言語のソースです##################### <宣言部元ソースと同じなので省略> //void sigcatch(int); int main() { unsigned short port = 9876; int srcSocket; int dstSocket; struct sigaction sa_sigint; struct sockaddr_in srcAddr; struct sockaddr_in dstAddr; int dstAddrSize = sizeof(dstAddr); int numrcv; char buffer[BUFFER_SIZE]; int status = 0; int select_cnt = 0; fd_set readfds; int n; struct timeval timeout; int re; char *toSendText = "This is a test"; memset(&srcAddr, 0, sizeof(srcAddr)); srcAddr.sin_port = htons(port); srcAddr.sin_family = AF_INET; srcAddr.sin_addr.s_addr = htonl(INADDR_ANY); srcSocket = socket(AF_INET, SOCK_STREAM, 0); bind(srcSocket, (struct sockaddr *) &srcAddr, sizeof(srcAddr)); listen(srcSocket, 1); printf("Waiting for connection ...\n"); FD_ZERO( &readfds ); FD_SET( srcSocket , &readfds ); n = srcSocket + 1; timeout.tv_sec = 10; timeout.tv_usec = 0; re = select( n , &readfds , NULL , NULL , &timeout ); if ( FD_ISSET( srcSocket , &readfds ) ){ dstSocket = accept(srcSocket, (struct sockaddr *) &dstAddr, &dstAddrSize); }else{ printf("accept timeout!\n"); exit(-1); } if ( dstSocket == -1 ){ printf("accept error![%d]\n",errno); exit(-1); } printf("Connected from %s\n", inet_ntoa(dstAddr.sin_addr)); <accept以後の処理元ソースと同じなので省略> <シグナルハンドラの関数は削除> //void sigcatch(int sig) { // printf("catch signal %d\n", sig); // if (sig == SIGALRM) { // printf("catch SIGALRM and exit.\n"); // } //}

その他の回答 (3)

  • mikaemi
  • ベストアンサー率50% (33/65)
回答No.4

シグナル動作は実行環境に依存するでしょうし動作も安全・確実とは限らないので、シグナル(システムの内部でシグナルを使って実装しているかどうか知らないが^^)を使わないで、やりたいことができるなら、シグナルを使わない select() や poll() を使う、tatsu99 さんの方法のほうがいいでしょうね^^

  • mikaemi
  • ベストアンサー率50% (33/65)
回答No.2

書き間違ってました^^『シグナルをキャッチしなければ』じゃなくて、キャッチするのはよくて、『sa_sigint.sa_flags = SA_RESTART;』を指定してるのが、リスタート指定なので、コメントアウトしたほうがいいと思います。『sa_sigint.sa_flags = SA_RESTART;』を無視するOSもあると思いますが、IamMasakiさんのOSはきちんとリスタートするんでしょう^^

  • mikaemi
  • ベストアンサー率50% (33/65)
回答No.1

シグナルをキャッチしていてデフォルト動作でない。IamMasakiさんのOSは、シグナルをキャッチして復帰したときに再実行という処理をするようになっているのではないですか?^^ シグナルをキャッチしなければ、意図通り動くのでは?

関連するQ&A

  • 1秒で動くインターバルタイマ

    こんにちは。私のプログラミング能力が無いために困ってます。 timer_settimeを使って、インターバルが1sのタイマで100s後に終了させたいのですが、できません。環境はRedHatLinux7.1Jです。 下記のプログラムを実行するとtimer_createとtimer_settimerのところで、errno=38 "function not implemented"とでます。原因、どうしたらよいかわかりません。どのように修正したらうごくんでしょうか? 教えてください。 #include <signal.h> #include <time.h> #include <error.h> #include <errno.h> extern int errno; timer_t timerid; struct itimerspec one_minute = { {60, 0}, {0, 0} } ; struct sigaction sigact; struct sigevent sigev; int i,end; void handler() { i++; if (i == 100) end = 1; printf("きてます\n"); } int main() { i=0; end=0; sigact.sa_handler = handler; sigact.sa_flags = 0; if (sigaction(SIGUSR1, &sigact, (struct sigaction *)NULL)== -1) { printf("%d:%s\n",errno,strerror(errno)); exit(1); } sigev.sigev_notify = SIGEV_SIGNAL; sigev.sigev_signo = SIGUSR1; if (timer_create(CLOCK_REALTIME, &sigev, &timerid) == -1) { printf("%d:%s\n",errno,strerror(errno)); exit(1); } if (timer_settime(timerid, 0, &one_minute, (struct itimerspec == -1) { printf("%d:%s\n",errno,strerror(errno)); exit(1); } while (!end){ pause(); } if (timer_delete(timerid) == -1) { perror("timer_delete"); exit(1); } return 0; } 宜しくお願いします。

  • LinuxでのC言語通信プログラムについて

    サーバーとクライアントで足し算を行うプログラムを実行するとサーバーからの計算結果が返ってきません。ソースコードは以下に示します。 クライアントのプログラム #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> int main(void) { int sockfd ; int tolen , fromlen ; struct sockaddr_in to_address , from_address ; int result ; int ch[3] ; sockfd = socket(AF_INET,SOCK_DGRAM,0); to_address.sin_family = AF_INET ; to_address.sin_addr.s_addr = INADDR_ANY ; to_address.sin_port = htons(9734) ; tolen = sizeof(to_address); bind(sockfd , (struct sockaddr *)&to_address , tolen); printf("A = "); scanf("%d",&ch[0]); printf("B = "); scanf("%d",&ch[1]); sendto(sockfd , ch , sizeof(ch) , 0 , (struct sockaddr *)&to_address , tolen); recvfrom(sockfd , ch , sizeof(ch) , 0 , (struct sockaddr *)&from_address , &fromlen); printf("A + B = %d \n",ch[2]); close(sockfd); exit(0); } サーバーのプログラム #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> int main(void) { int ch[3] ; int sockfd ; int tolen , fromlen ; struct sockaddr_in to_address ; struct sockaddr_in from_address ; sockfd = socket(AF_INET,SOCK_DGRAM,0); to_address.sin_family = AF_INET ; to_address.sin_addr.s_addr = INADDR_ANY ; to_address.sin_port = htons(9734) ; tolen = sizeof(to_address); bind(sockfd , (struct sockaddr *)&to_address , tolen); while(1) { printf("server waiting\n"); recvfrom(sockfd , ch , sizeof(ch) , 0 , (struct sockaddr *)&from_address , &fromlen); ch[2] = ch[0] + ch[1] ; sendto(sockfd , ch , sizeof(ch) , 0 , (struct sockaddr *)&from_address , fromlen); } }

  • チャットプログラムでのselectの使い方について

    linux開発環境でC言語を用いて1対5程度のチャットプログラムを作成しています。クライアントから送信された内容はサーバに表示されるのですが、この内容を他のクライアントにも表示したいです。そこでselect関数を用いたいのですが、どこにどのようなコードで挿入すればよいかわかりません。以下にプログラムを載せるので、できれば詳しいコードで回答をよろしくお願いいたします。 サーバプログラム #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/wait.h> #include <unistd.h> #include <signal.h> #include <netdb.h> #define PORT 5320 void kill_zombie_process(int sig); void close_process(int unused); char *show_ip(char *ip_address); int main(void) { int soc, acc, size; char buffer[80]; struct sockaddr_in client, server; struct hostent *server_host; pid_t pid; char host_name[257]; int temp; memset(host_name, 0, sizeof(host_name)); gethostname(host_name, 256); server_host = gethostbyname(host_name); printf("\n-------- informations of server ----------\n"); printf("Host name:%s\n", host_name); printf("IP = %s\n", show_ip(server_host->h_addr)); printf("\n\n"); soc = socket(AF_INET, SOCK_STREAM, 0); memset((char *)&server, 0, sizeof(server)); server.sin_family = AF_INET; server.sin_addr.s_addr = htonl(INADDR_ANY); server.sin_port = htons(PORT); bind(soc, (struct sockaddr *)&server, sizeof(server)); size = sizeof(client); listen(soc, 5); signal(SIGINT, close_process); signal(SIGCHLD, kill_zombie_process); while(1) { acc = accept(soc, (struct sockaddr *)&client, &size); pid = fork(); if(pid == 0) { close(soc); while(1) { memset(buffer, '\0', sizeof(buffer)); recv(acc, buffer, 80, 0); printf("%s> ", show_ip((char *)&client.sin_addr)); printf("%s", buffer); if(strncmp(buffer, "exit", 4) == 0) break; } close(acc); exit(0); } else { close(acc); } } return 0; } void kill_zombie_process(int sig) { while(waitpid(-1, NULL, WNOHANG) > 0); signal(SIGCHLD, kill_zombie_process); } void close_process(int unused) { exit(0); } char *show_ip(char *ip_address) { static char ip[7]; char ipnum[4]; bcopy(ip_address, ipnum, 4); sprintf(ip, "%u.%u.%u.%u",(unsigned char)ipnum[0], (unsigned char)ipnum[1], (unsigned char)ipnum[2],(unsigned char)ipnum[3]); return ip; } クライアントプログラム #include<stdio.h> #include<string.h> #include<stdlib.h> #include<sys/types.h> #include<sys/socket.h> #include<netinet/in.h> #include<arpa/inet.h> #define PORT 5320 int main(int argc, char *argv[]) { int soc; char message[80],ip_address[16]; struct sockaddr_in server; if(argc == 1) { printf("引数にIPアドレスが必要です/n"); exit(0); } strcpy(ip_address,argv[1]); soc = socket(AF_INET,SOCK_STREAM,0); memset((char *)&server,0,sizeof(server)); server.sin_family = AF_INET; server.sin_port = htons(PORT); server.sin_addr.s_addr = inet_addr(ip_address); connect(soc,(struct sockaddr *)&server,sizeof(server)); while(1) { printf("メッセージを入力してください:"); fgets(message,80,stdin); send(soc,message,strlen(message),0); if(strncmp(message,"exit",4) == 0)break; } close(soc); return 0; }

  • Linuxのsocket接続でacceptできない

    Ubuntu 10.10 + gcc4.4 + eclipse で C言語プログラミングをしています。 ソケットを使用したプログラムを試していたのですが、思うように動作しません。 作成したプログラムは以下のようなものです。 ・ローカルマシン上で、サーバプログラム、クライアントプログラムを用意する ・サーバ側はソケット作成後、クライアントが接続するまで listen する ・クライアントはサーバに接続したら、接続した旨を表示する という初歩的なものです。 問題は、サーバ側が accept したときに戻り値 -1 を返却して終了してしまうことです。 以下が作成したソースです。 ■■■▼ サーバ側ここから ▼■■■ #include <sys/socket.h> #include <sys/un.h> #include <stdlib.h> #include <stdio.h> int main(int argc, char *argv[]) { int sockfd; struct sockaddr_un srv; socklen_t socklen; /* ソケット名をコマンド入力で受け取る */ if(argc != 2) { puts("USAGE: mksock <filename>"); exit(EXIT_FAILURE); } /* ソケット作成 */ if((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0){ exit(EXIT_FAILURE); } /* srv 初期化 */ memset(&srv, 0, sizeof(srv)); srv.sun_family = AF_UNIX; strncpy(srv.sun_path, argv[1], sizeof(srv.sun_path)); /* バインド */ if((bind(sockfd, (struct sockaddr *)&srv, SUN_LEN(&srv))) < 0){ exit(EXIT_FAILURE); } /* クライアントからの接続待ち */ if((listen(sockfd, 5)) < 0) { exit(EXIT_FAILURE); } printf("socket available: %s, sockfd=%d\n", srv.sun_path, sockfd); /* 接続がある限りくりかえす */ int sockResult; while(1) { sockResult = accept(sockfd, (struct sockaddr *)&srv, &socklen); printf("sockResult = %d, sun_path=%s\n", sockResult, srv.sun_path); if (sockResult < 0) break; puts("new connection granted"); } puts("mksock end"); exit(EXIT_SUCCESS); } ■■■▲ サーバ側ここまで ▲■■■ ●●●▼ クライアント側ここから ▼●●● #include <sys/socket.h> #include <sys/un.h> #include <stdlib.h> #include <stdio.h> int main(int argc, char *argv[]) { int sockfd; struct sockaddr_un cli; socklen_t socklen; /* ソケット名をコマンド入力で受け取る */ if(argc != 2) { puts("USAGE: sockconn <filename>"); exit(EXIT_FAILURE); } /* ソケット作成 */ if((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0){ exit(EXIT_FAILURE); } /* クライアント設定 */ memset(&cli, 0, sizeof(cli)); cli.sun_family = AF_UNIX; strncpy(cli.sun_path, argv[1], sizeof(cli.sun_path)); /* サーバへ接続 */ socklen = SUN_LEN(&cli); if(connect(sockfd, (struct sockaddr *)&cli, socklen)) { exit(EXIT_FAILURE); } printf("connected to socket %s\n", cli.sun_path); exit(EXIT_SUCCESS); } ●●●▲ クライアント側ここまで ▲●●● これから作成されたバイナリを同一フォルダに置いて、作成ユーザで、カレントディレクトリで実行しました。 以下が実行時の入出力です(カッコ内は実行順序)。 ■▼ サーバ側ここから ▼■ $ ./mksock jjj1…(1) $ socket available: jjj1, sockfd=3 $ sockResult = -1, sun_path=jjj1 $ mksock end ■▲ サーバ側ここから ▲■ ●▼ クライアント側ここから ▼● $ ./sockconn jjj1…(2) $ connected to socket jjj1 ●▲ クライアント側ここから ▲● 上記のように、サーバ側が accept 時に -1 を返却しています。 パーミッションについては以下になっています。 srwxr-xr-x 1 hoge hoge 0 2011-09-04 21:36 jjj1 -rwxr--r-- 1 hoge hoge 86870 2011-09-04 21:36 mksock -rwxr--r-- 1 hoge hoge 86775 2011-09-04 21:36 sockconn パーミッションを見る限り、ソケットファイルにはアクセスできているかと。 おそらく環境周りではないかと思いますが、考えつきません。 linux プログラミングに詳しいかた、よろしくお願いいたします。

  • 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; } 先生によると、クライアントは同じもので良いそうです。 誰か、助けて下さい。

  • VxWorks 6.4ソケット接続について。

    VxWorks 6.4ソケット接続について。 connectWithTimeout()でサーバへの接続ができません。戻り値が常にERROR。connect() だとうまくいくのですが、何が原因なのでしょうか? 下記にソースコードを提示します #include "vxWorks.h" #include "stdio.h" #include "stdlib.h" #include "types.h" #include "net/mbuf.h" #include "socket.h" #include "net/socketvar.h" #include "socklib.h" #include "inetLib.h" void tmain( void ) { #define IP_ADDRS_SERVER "193.9.200.2" struct timeval TimeOut; struct sockaddr_in Srv; static int nSock; int ret=0; int status=0; do{ nSock = socket(AF_INET, SOCK_STREAM, 0); TimeOut.tv_sec = 10L ; TimeOut.tv_usec = 0L ; Srv.sin_family = AF_INET ; Srv.sin_port = htons(12000) ; Srv.sin_addr.s_addr = inet_addr(IP_ADDRS_SERVER) ; //↓これだとうまくいく↓ // if ( connect(nSock, (struct sockaddr *)&Srv, sizeof(Srv) ) == ERROR ) { //↓これだとうまくいかない↓ if ( connectWithTimeout(nSock, (struct sockaddr *)&Srv, sizeof(Srv), &TimeOut ) == ERROR ) { ret = close(nSock); } else { status=1; } }while(status==0); }

  • Winsockについての質問

    Winsockで、「GET / HTTP/1.1」というリクエストを「127.0.0.1(自分自身)」に送って(サーバーはAPACHE2)ドキュメントルートにある「index.html」を見る。 というプログラムを作ったのですが、受信ができません。 受信できるにはどうすればいいか教えてください。 尚以下がそのプログラムです。 #include<stdio.h> #include<winsock2.h> int main(){ SOCKET hsock; struct sockaddr_in serverOption; char buf[1024]; int Error; int func_Error; WSADATA wsadata; func_Error=WSAStartup(MAKEWORD(2,0),&wsadata); if(MAKEWORD(2,0)!=wsadata.wVersion){ fprintf( stderr, "Winsock version error\n"); return -1; } hsock=socket(AF_INET,SOCK_STREAM,0); if(!hsock){ printf("ソケット作成エラー"); } serverOption.sin_family=AF_INET; serverOption.sin_addr.s_addr=inet_addr("210.81.150.5"); serverOption.sin_port=htonl(80); func_Error=connect(hsock,(struct sockaddr *)&serverOption,sizeof(serverOption)); if(!func_Error){ printf("接続エラー"); } func_Error=send(hsock,"GET / HTTP/1.1",strlen("GET / HTTP/1.1"),0); if(!func_Error){ printf("データが送れない。残念ですた"); } Error=recv(hsock,buf,sizeof(buf),0); if( Error <= 0) { printf("受信不可能"); return -1; } buf[Error]='\0'; printf("%s",buf); closesocket(hsock); WSACleanup(); return 0; }

  • スレッドとメッセージキューに関して

    現在、下記のようなプログラムを作成しています。 内容は、メッセージキューを受信するスレッドを生成するというイメージです。 処理内容は下記のようになります。  (1)メッセージキューの生成  (2)スレッド生成(メッセージキュー受信側)  (3)スレッド停止  (4)メッセージキューの削除 しかし、(3)のスレッド停止を実施しても、(4)のメッセージキューの削除以降にて、msgrcvのエラーが出力されてしまいます。 スレッド停止を行ったことから、TestThreadは動作しなくなり、(4)のメッセージキューの削除にて、エラーともならずに終了することを望んでりますが、上手くいきません。 下記に作成しているプログラムを記載いたします。 正常終了をするには何がいけないのでしょうか? ご教授宜しくお願い致します。 [test.cc] ---------------------------------------------------------------- #include <time.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <ctype.h> #include <stdlib.h> #include <pthread.h> #include <stdlib.h> #include <sys/ipc.h> #include <sys/msg.h> // メソッドポインタ定義 typedef void (*testT); // スレッドID pthread_t threadId; // メッセージキュー識別子 int msqId; // 送受信するメッセージ struct msgbuf{ long int type; char data[BUFSIZ]; }; // テストスレッド void TestThread() { // メッセージ struct msgbuf message; while( 1 ) { printf("### TEST ###\n"); printf("msq start\n"); // 受信 if( msgrcv( msqId, &message, BUFSIZ, 0, 0 ) == -1) { printf("ERR! msgrcv errno[%d]\n", errno); continue; } printf("msq ed\n"); sleep(1); } return; } // メイン int main(int argc, char *argv[]) { // メッセージキュー識別子退避変数 int testMsqid; // スレッド操作リターン値 int status; // スレッドa用のパラメータ pthread_t thread_test; printf("### TEST START ###\n"); // メッセージキューの作成 if( (testMsqid = msgget((key_t)1111, 0666 | IPC_CREAT)) == -1 ) { printf("ERR! CREATE bkMsqId[%d]\n", testMsqid); return 1; } // メッセージキュー識別子を共通変数に設定 msqId = testMsqid; printf("msgget OK\n"); sleep(5); // スレッドを生成 status = pthread_create(&thread_test, NULL, (void*(*)(void*))TestThread, (void*)NULL); if(status!=0) { printf("pthread_create ng\n"); return 1; } printf("pthread_create OK\n"); sleep(5); // スレッド停止 status = pthread_cancel(thread_test); // スレッド停止結果 if ( status != 0 ) { printf("pthread_cancel ng\n"); return 1; } printf("pthread_cancel OK\n"); sleep(5); // メッセージキューの削除 if ( msgctl( msqId, IPC_RMID, NULL) == -1 ) { printf("msqId[%d] errno[%d]\n", msqId, errno); return 1; } printf("msgctl OK\n"); sleep(5); printf("### TEST E N D ###\n"); return 0; } ----------------------------------------------------------------

  • windows版C++ソケットプログラムエラー

    windows版のC++のソケット通信プログラムです。 server、clientそれぞれのプログラムにおいてエラーがでます。 修正をお願いします。 server側 ・エラー内容 'status' : 定義されていない識別子です。 ・プログラム status = closesocket(dstSocket); break; ・全体プログラム #include <stdio.h> #include <winsock2.h> #include <ws2tcpip.h> #define BUFFER_SIZE 256 int main() { /* ポート番号、ソケット */ unsigned short port = 9876; int srcSocket; // 自分 int dstSocket; // 相手 /* sockaddr_in 構造体 */ struct sockaddr_in srcAddr; struct sockaddr_in dstAddr; int dstAddrSize = sizeof(dstAddr); /* 各種パラメータ */ int numrcv; char buffer[BUFFER_SIZE]; /************************************************************/ /* Windows 独自の設定 */ WSADATA data; WSAStartup(MAKEWORD(2,0), &data); /* sockaddr_in 構造体のセット */ memset(&srcAddr, 0, sizeof(srcAddr)); srcAddr.sin_port = htons(port); srcAddr.sin_family = AF_INET; srcAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* ソケットの生成 */ srcSocket = socket(AF_INET, SOCK_STREAM, 0); /* ソケットのバインド */ bind(srcSocket, (struct sockaddr *) &srcAddr, sizeof(srcAddr)); /* 接続の許可 */ listen(srcSocket, 1); /* 接続の受付け */ printf("Waiting for connection ...\n"); dstSocket = accept(srcSocket, (struct sockaddr *) &dstAddr, &dstAddrSize); printf("Connected from %s\n", inet_ntoa(dstAddr.sin_addr)); /* パケット受信 */ while(1) { numrcv = recv(dstSocket, buffer, BUFFER_SIZE, 0); if(numrcv == 0 || numrcv == -1) { status = closesocket(dstSocket); break;                 ←ここです!!! } printf("received: %s\n", buffer); } /* Windows 独自の設定 */ WSACleanup(); } client側 ・エラー内容 1 'stAddr' : 定義されていない識別子です。 2 '.sin_addr' の左側はクラス、構造体、共用体でなければなりません 3 '.S_un' の左側はクラス、構造体、共用体でなければなりません 4 '.S_addr' の左側はクラス、構造体、共用体でなければなりません 5 'i' : 定義されていない識別子です。 6 'i' : 定義されていない識別子です。 7 'i' : 定義されていない識別子です。 ・プログラム 1~4 stAddr.sin_addr.s_addr = inet_addr(destination); 5~7 for(i=0; i<10; i++) ・全体プログラム #include <stdio.h> #include <winsock2.h> #include <ws2tcpip.h> int main() { /* IP アドレス、ポート番号、ソケット */ char destination[80]; unsigned short port = 9876; int dstSocket; /* sockaddr_in 構造体 */ struct sockaddr_in dstAddr; /* 各種パラメータ */ int status; int numsnt; char *toSendText = "This is a test"; /************************************************************/ /* Windows 独自の設定 */ WSADATA data; WSAStartup(MAKEWORD(2,0), &data); /* 相手先アドレスの入力 */ printf("Connect to ? : (name or IP address) "); scanf("%s", destination); /* sockaddr_in 構造体のセット */ memset(&dstAddr, 0, sizeof(dstAddr)); dstAddr.sin_port = htons(port); dstAddr.sin_family = AF_INET; stAddr.sin_addr.s_addr = inet_addr(destination);                 ←ここです!!! /* ソケット生成 */ dstSocket = socket(AF_INET, SOCK_STREAM, 0); /* 接続 */ printf("Trying to connect to %s: \n", destination); connect(dstSocket, (struct sockaddr *) &dstAddr, sizeof(dstAddr)); /* パケット送出 */ for(i=0; i<10; i++) { ←ここです!!! printf("sending...\n"); send(dstSocket, toSendText, strlen(toSendText)+1, 0); Sleep(1000); } /* Windows 独自の設定 */ closesocket(dstSocket); WSACleanup(); } です。 読みづらいとは思いますがよろしくお願いします(><)

  • c言語のaccept関数が待機を行いません

    c言語のaccept関数が待機を行いません 現在C言語によるプログラミングを勉強中で、 「Windows ゲームプログラミング」という書籍を教材に ネットワーク通信のプログラミングを行っております。 ネットワーク通信のプログラミングは初めてで 現在一つの壁にぶつかっております。 どうか護教授をお願い致します。 下記のサーバー側のコードですが、 (1)ソケットを作成して、bind関数でアドレスと関連付ける (2)listen関数で接続を準備する (3)accept関数でクライアントが接続するまで待機する (4)while文の中でクライアントからのメッセージを受け取る という目的で作成いたしましたが、クライアントからの接続はしていないはずなんですが、 どうもaccept関数で待機を行わず、while文に進んでしまい、無限ループに突入してしまいます。 accept関数の戻り値を確認すると「INVALID_SOCKET」でした。 現在はこのサーバーに接続するシステムは作成していないので接続はないと思います。 ポート番号などを変更してもダメでした。 お恥ずかしい質問かもしれませんが、どうかよろしくお願い致します。 以下コード WSADATA wsaData; sturuct sockaddr_in hostAddr,clAddr; SOCKET s,client; char buffer[1024]; int length; if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0) return; (1) s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); hostAddr.sin_family=AF_INET; hostAddr.sin_port=ポート番号; hostAddr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1"); bind(s,&hostAddr,sizeof(struct sockaddr_in)); (2) listen(s,1); printf("クライアントからの接続を待機...\n"); (3) client=accept(s,&clAddr,&length); printf("クライアントからの接続を確認\n受信を待機...\n"); (4) while(1){ length=recv(client,buffer,1024,0); buffer[length]=0; printf("文字列を受信:%s\n",buffer); if(strcmp(buffer,"exit")==0) break; } shutdown(client,SD_BOTH); closesocket(client); closesocket(s); WSACleanup(); return 0;

専門家に質問してみよう