多人数のチャットソフトを開発中に問題発生!サーバを挟んで1対多のチャットがうまくいかない

このQ&Aのポイント
  • Winsockを使用して開発中の多人数チャットソフトで、1対1のチャットは成功していますが、サーバを挟んでの1対多のチャットが上手くいきません。質問者はサーバがクライアントごとにスレッドを作成し、ディスクリプタを配列に格納して送信したいと考えています。
  • しかし、実行すると無数のスレッドが作成され、プログラムが強制終了してしまいます。質問者は初心者のため、プログラムのミスがある場合に教えて欲しいとしています。
  • また、質問者はアイデアがあれば教えて欲しいとも述べています。
回答を見る
  • ベストアンサー

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

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); } } これを実行するとスレッドが無数に作成され、強制終了させられてしまいます。 初級者なのでプログラムのミスがあったら教えて下さい。 違うアイディアもあったら教えて欲しいです。見にくいと思いますがよろしくお願いします。。。。

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

  • ベストアンサー
  • unacyo
  • ベストアンサー率51% (35/68)
回答No.2

気がついたことを幾つか。 1.accept()の第三引数には、第二引数に渡すバッファサイズをセットしておかないとダメです。 Ssize = sizeof( Ssize ); Csock[i] = accept( s, (struct sockaddr *)&Saddr, &Ssize ); たぶん、この値が不定値でエラーとなっているため、ブロッキングされずに、大量にスレッドが生成されているのかも? 2.一文字ずつ受信/配信より、一行ずつ処理しないと、多人数は表示がおかしくなります。 同時に入力されると、配信された文章がチャンポンになりませんか? また、入力していた文章を、ログをみて書き直すこともあるでしょうから、 取り消しが出来るように、一行づつクライアントから送ってもらい、サーバで分散した方が、 使いやすいと思いますよ?

その他の回答 (1)

  • drum_KT
  • ベストアンサー率43% (1108/2554)
回答No.1

while(1){ Csock[i] = accept(s,(struct sockaddr *) &Saddr, &Ssize); CreateThread(Csock[i]);  //クライアントごとにスレッドを作ってるつもり i++; } うん。これじゃあ確かにあっという間にスレッドが無数にできあがるよね。無限ループだから。

関連するQ&A

  • 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); } }

  • C言語で作成するチャットについて

    LinuxでC言語のチャットプログラムを作成しています。プログラムを作ってみましたがうまく動きません。悪い個所が分からないのでお力を貸して頂きたいです課題の提出が迫っているので、よろしくお願いいたします。 <server> #include省略 #define PORT 5320 char *show_ip(char *ip_address); int main(void){ int soc, acc, size, child[3],width,i,count,pos,ret; char buffer[80]; struct sockaddr_in client, server; struct sockaddr_storage from; struct hostent *server_host; socklen_t len; fd_set mask; 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); for (i = 0; i < 3; i++){ child[i] = -1; } for (;;) { FD_ZERO(&mask); FD_SET(soc, &mask); for (i = 0; i < 3; i++) { if (child[i] != -1){ FD_SET(child[i], &mask); if(child[i]+1 > width){ width = child[i]+1; } } } switch(select(soc+1, (fd_set *) &mask, NULL, NULL, NULL)) { case -1: perror("select"); break; case 0: break; default: if (FD_ISSET(soc, &mask)){ len = (socklen_t) sizeof(from); if((acc = accept(child[i], (struct sockaddr *)&from, &len)) == -1){ if(errno != EINTR){ perror("accept"); } }else{ if(child[0]&&child[1]&&child[2]!=-1){ fprintf(stderr,"child is full : cannot accept\n"); close(acc); }else{ if(child[0] == -1){ child[0] = acc; }else if(child[1] == -1){ child[1] = acc; }else{ child[2] = acc; } } } } for(i=0;i<3;i++){ if(child[i]!=-1){ if(FD_ISSET(child[i],&mask)){ memset(buffer, '\0', sizeof(buffer)); recv(child[i], buffer, 80, 0); printf("%s> ", show_ip((char *)&client.sin_addr)); printf("%s", buffer); if(strncmp(buffer, "exit", 4) == 0) break; for(i=0;i<3;i++) { send(child[i],show_ip((char *)&client.sin_addr),80,0); send(child[i],buffer,80,0); close(child[i]); } (void) close(child[i]); child[i] = -1; } } break; } } } } 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; } <client> #include省略 #define STDIN_FD 0 #define PORT 5320 int select_func(int sockfd); void err_func(char *msg){ perror(msg); exit(EXIT_FAILURE); } int main(int argc, char **argv){ int sockfd, len; char buf[BUFSIZ]; struct sockaddr_in serv; unsigned short port; if(argc != 3){ printf("usage: progname serv_ip serv_port\n"); exit(EXIT_FAILURE); } if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) err_func("socket"); serv.sin_family = PF_INET; port = (unsigned short)atoi(argv[2]); serv.sin_port = htons(port); inet_aton(argv[1], &(serv.sin_addr)); if(connect(sockfd, (struct sockaddr *)&serv, sizeof(struct sockaddr_in)) < 0) err_func("connect"); do{ if(select_func(sockfd) == 0){ len = recv(sockfd, buf, BUFSIZ, 0); buf[len] = '\0'; printf("-> %s\n", buf); }else{ len = read(STDIN_FD, buf, BUFSIZ); len = send(sockfd, buf, len, 0); } }while(strncmp(buf, "EXIT\r\n", 6) != 0 && strncmp(buf, "EXIT\n", 5) != 0); close(sockfd); return 0; } int select_func(int sockfd){ fd_set rfds; FD_ZERO(&rfds); FD_SET(sockfd, &rfds); FD_SET(STDIN_FD, &rfds); if(select(sockfd+1, &rfds, NULL, NULL, NULL) < 0) err_func("select"); if(FD_ISSET(STDIN_FD, &rfds)) return STDIN_FD; return sockfd; }

  • 延々と受信し続けるwinsockのrecv

    以下のサーバープログラムを用いて、 (acceptしたらスレッド作成し、作成が終ったということをクライアントに知らせるために文字列送信後受信待機している) #include <winsock2.h> #include <vector> #include <process.h> #include <algorithm> char *Ver = "0.00"; using namespace std; unsigned __stdcall Patch( void *Sock ); int main() { ----WSADATA wsaData; --------WSAStartup( MAKEWORD(2,0), &wsaData ); ----SOCKET RecvSock = socket( AF_INET, SOCK_STREAM, 0 ); ----SOCKET SendSockBuf; ----vector<SOCKET> SendSock; ----fd_set ConnectFds, SubConnectFds; ----struct sockaddr_in Recv, Send; ----int len = sizeof(Send); ----Recv.sin_family = AF_INET; ----Recv.sin_port = htons(55555); ----Recv.sin_addr.S_un.S_addr = INADDR_ANY; --------bind(RecvSock, (struct sockaddr *)&Recv, sizeof(Recv) ); ----FD_ZERO( &SubConnectFds ); --------FD_SET( RecvSock, &SubConnectFds ); ----listen( RecvSock, 5 ); ----vector<unsigned int> thID; ----vector<HANDLE> hTh; ----struct timeval tv; --------tv.tv_sec = 0; --------tv.tv_usec = 0; ----while(1) ----{ --------memcpy( &ConnectFds, &SubConnectFds, sizeof(fd_set) ); --------select( 0, &ConnectFds, NULL, NULL, &tv ); --------if ( FD_ISSET(RecvSock, &ConnectFds) ) --------{ ------------SendSockBuf = accept(RecvSock, (struct sockaddr *)&Send, &len); ------------if( SendSockBuf != INVALID_SOCKET) ------------{ ----------------SendSock.push_back( SendSockBuf ); ----------------thID.push_back( hTh.size() ); ----------------hTh.push_back( (HANDLE)_beginthreadex(NULL, 0, Patch, &SendSock[hTh.size()], 0, &thID[hTh.size()]) ); ------------} --------} ----} ----closesocket(RecvSock); ----WSACleanup(); ----return 0; } unsigned __stdcall Patch( void *Sock ) { ----SOCKET *SendSock = (SOCKET *)Sock; ----send( *SendSock, Ver, 5, 0 ); ----char Str[5]; ----while( Flag == 0 ) ----{ --------recv( *SendSock, Str, 5, 0 ); ----} ----closesocket( *SendSock ); ----return 0; } 以下のようなクライアントプログラムで文字を送信すると、 #include <WinSock2.h> using namespace std; void main() { ----WSADATA wsaData; --------WSAStartup( MAKEWORD(2,0), &wsaData ); ----SOCKET Sock = socket( AF_INET, SOCK_STREAM, 0 ); ----struct sockaddr_in Addr; --------Addr.sin_family = AF_INET; --------Addr.sin_port = htons(55555); --------Addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); ----connect( Sock, (struct sockaddr *)&Addr, sizeof(Addr) ); ----char str[5]; ----recv( Sock, str, 5, 0 ); ----send( Sock, "0.00", 5, 0); ----shutdown( Sock, 2 ); ----closesocket( Sock ); } クライアントプログラムは終了しているのにサーバープログラムは"0.00"を受信し続けます。 どこがおかしいのか分からないので教えてください

  • 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{     //受信データがなかったときの処理   } }

  • UDP通信について

    UDP通信で困っています。 TCP/IP通信はすぐにうまくいったのですが、 UDPの簡単なサンプルがちゃんと動きません。 間違いがあればご指摘ください。 よろしくお願いします。 (クライアント側ソース int sock; struct sockaddr_in din; memset(&din, 0, sizeof(din)); din.sin_port = htons(50050); din.sin_family = AF_INET; din.sin_addr.s_addr = inet_addr("サーバーIP"); sock = socket(AF_INET, SOCK_DGRAM, 0); int buf = 12345; sendto(sock,(char*)&buf,sizeof(int),0,(struct sockaddr*)&din,sizeof(struct sockaddr_in)); (サーバー側ソース int sock; struct sockaddr_in sin; sock = socket(AF_INET, SOCK_DGRAM, 0); memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(50050); sin.sin_addr.s_addr = htonl(INADDR_ANY); if(bind(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) { return(1); } struct sockaddr_in fromaddr; socklen_t len = sizeof(struct sockaddr_in); int buf; recvfrom(sock,(char*)&buf,sizeof(int),0,(struct sockaddr*)&fromaddr,&len); printf("recv:%d\n",buf);

  • UDP通信について

    前回のことでかなり言われたので改変版を見てもらいたいと思います。 TCPと伝えていましたが今回、UDPに変えました。 ヘッダーはこのようになっております。 ==wsock.h== #include <Windows.h> #include <stdio.h> #pragma comment(lib,"WSock32.lib") #define PORT_NO 8000 ポート番号 #define SERVER_NAME "" enum MINE{ NONE, SERVER, CLIENT }; ソケット通信 class WSOCK{ private: WSADATA wsaData; SOCKET s; SOCKADDR_IN saddr; int rtn; int state; MINE mineFlg; char szStr[256]; エラーメッセージ用 u_short port; 変換後のポート番号 int fromlen; 受信したサイズ HOSTENT *lpHost; ホスト情報 ファイルディスクプリタをまとめた構造体 //→ソケット判別する為の管理情報 fd_set fds,readfds; public: char szRcvBuf[1024]; 受信バッファ char szSndBuf[1024]; 送信バッファ SOCKADDR_IN from; ソケットアドレス構造体 WSOCK(); ~WSOCK(); bool ServerRcv(); 受信 bool ServerSnd();送信 bool CliantRcv();受信 bool CliantSnd();送信 void SarverSet(); void ClientSet(); bool EnumMyIPAddress(); }; ==wsock.cpp== #include "wsock.h" コンストラクタ WSOCK::WSOCK(){ //WinSock初期化 rtn = WSAStartup(MAKEWORD(2,2),&wsaData); if(rtn != 0){ MessageBox(NULL,"WSAStartup失敗", "ERROR",MB_OK); state = -1; } ソケットを開く s = socket(AF_INET,SOCK_DGRAM,0); if(s<0){ MessageBox(NULL,"ソケットをオープンできません", "eRROR",MB_OK); WSACleanup(); state = 2; } 0で初期化 memset(&saddr,0,sizeof(SOCKADDR_IN)); saddr.sin_family = AF_INET;//アドレスファミリー saddr.sin_port = htons(PORT_NO);//ポート mineFlg = SERVER; サーバ側設定 if(mineFlg == SERVER) { SarverSet(); } if(mineFlg == CLIENT) {クライアント ClientSet(); } } WSOCK::~WSOCK(){ closesocket(s); ソケットのリソース解放 rtn = WSACleanup(); if(rtn == SOCKET_ERROR){ MessageBox(NULL,"WSACleanup失敗","ERrOR",MB_OK); state = -2; } } //受信 bool WSOCK::ServerRcv(){ 読み込み用fd_setの初期化 selectが毎回内容を上書きしてしまうので毎回初期化 memcpy(&fds,&readfds,sizeof(fd_set)); struct timeval timeout = {0,0};   //{1秒以上の部分()s、1秒以下の部分(ms)} fdsに設定されたソケットが読み込み可能になるまで待つ select(0,&fds,NULL,NULL,&timeout); ソケット読み込み可能データがある場合 if(FD_ISSET(s,&fds)){ fromlen = (int)sizeof(from); //nullで初期化 memset(szRcvBuf,'\0',sizeof(szRcvBuf)); //受信処理 rtn = recvfrom(s,szRcvBuf,(int)sizeof(szRcvBuf)-1,0, (SOCKADDR*)&from,&fromlen); if(rtn == SOCKET_ERROR){ MessageBox(NULL,"recvfromエラー","ERRoR",MB_OK); return false; } } szRcvBuf[rtn] | '\0';//NULLコード if(strcmp(szRcvBuf,"c_end") == 0){ MessageBox(NULL,"クライアントが接続を切りました","ERROr",MB_OK); return false; } return true; } 送信 bool WSOCK::ServerSnd(){ char buf[1024]; memset(buf,0,sizeof(buf)); //_snprintf:書式指定文字付きデータ書き込み _snprintf(buf,sizeof(buf),"data to port 8000"); //送信処理 rtn = sendto(s,szSndBuf,(int)strlen(szSndBuf)+1, 0,(LPSOCKADDR)&from, 送り先サーバ/クライアント sizeof(from)); サイズ if(rtn != (int)strlen(szSndBuf)+1){ MessageBox(NULL,"sendtoエラー","サーバーエラ",MB_OK); closesocket(s); WSACleanup(); return false; } return true; } 受信 bool WSOCK::CliantRcv(){ fromlen = (int)sizeof(from); //nullで初期化 memset(szRcvBuf,'\0',sizeof(szRcvBuf)); //受信処理 rtn = recvfrom(s,szRcvBuf,(int)sizeof(szRcvBuf)-1,0, (SOCKADDR*)&from,&fromlen); if(rtn == SOCKET_ERROR){ MessageBox(NULL,"recvfromエラー","ERRoR",MB_OK); return false; } szRcvBuf[rtn] | '\0'; //NULLコード if(strcmp(szRcvBuf,"s_end") == 0){ MessageBox(NULL,"接続を切りました","ERROr",MB_OK); return false; } return true; } 送信 bool WSOCK::CliantSnd(){ 送信処理 rtn = sendto(s,szSndBuf,(int)strlen(szSndBuf)+1, 0,(LPSOCKADDR)&saddr, 送り先サーバ/クライアント sizeof(saddr)); サイズ if(rtn != (int)strlen(szSndBuf)+1){ MessageBox(NULL,"sendtoエラー","erROR",MB_OK); closesocket(s); WSACleanup(); return false; } return true; } void WSOCK::SarverSet(){ saddr.sin_addr.s_addr = htonl(INADDR_ANY); ソケットにローカルアドレスを関連付ける if(bind(s,(LPSOCKADDR)&saddr, (int)sizeof(saddr)) == SOCKET_ERROR){ MessageBox(NULL,"bindエラー","er",MB_OK); closesocket(s); WSACleanup(); state = -3; } FD_ZERO(&readfds); FD_SET(s,&readfds); } void WSOCK::ClientSet(){    クライアント側設定    ホスト名からホスト情報を取得 lpHost = gethostbyname(SERVER_NAME); サーバのアドレスをセット memcpy(&(saddr.sin_addr), lpHost->h_addr_list[0], //サーバのアドレス lpHost->h_length); } となっております。

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

  • Winsockを用いてデータを交互に送信しあいたい

    チャットプログラムではないのですが、チャットプログラムのソースが参考になると思いネットで調べて見ましたが見つからなかったので質問させていただきます。 したいのは、.rarなどの圧縮されたファイル(サイズはGB単位)の送信(TCP)です。 トータルのファイルサイズとファイル名をBYTE配列に書き込む BYTE配列のサイズを送信後、BYTE配列を送信 (とりあえずここでトータルサイズを4MB(4×1024×1024)で割った商をQ、余りをRと置いておく) ファイルをバイナリ読み込みモードで開く 受け取ったという合図を受け取ったらファイルの先頭から4MB読み込んでBYTE配列に入れて送信 受け取ったという合図を受け取ったら続きから4MB読み込んでBYTE配列に入れて送信 ↑を先頭の分も合わせてQ回繰り返す。 受け取ったという合図を受け取ったら続きからRバイト読み込んでBYTE配列に入れて送信 ファイルを閉じる としたのですが、 ファイルの先頭から4MBは送信できているようなのですが、そこから先に進みません。 具体的には、4MBの受信したという合図を送っても、send関数が-1を返すようです プログラムは以下の通りです Server Winsockの設定やファイルのトータルサイズ云々なので略 listen( RecvSock, 5 ); fp = fopen( FileName, "rb" ); int TotalSend = 0; int i = -1; SendSock = accept(RecvSock, (struct sockaddr *)&Send, &len);//コメントアウトを外す場合はこれはコメントアウト while(1) { //SendSock = accept(RecvSock, (struct sockaddr *)&Send, &len); if( i == -1 ) { send( SendSock, (char *)&FileSize, 4, 0 ); //↓の配列サイズを入れたBYTE配列 send( SendSock, (char *)Buff, Size, 0 );//トータルファイルサイズとファイル名 delete []Buff;//BYTE *Buff = new BYTE[FileSize]としたため } //フラグ受信 { recv( SendSock, (char *)&i, 4, 0 ); } if( i == Q ) { fread( SendBuff, R, 1, fp ); while( TotalSend < R ) { TotalSend += send( SendSock, (char *)&SendBuff[TotalSend], R-TotalSend, 0 ); } } else if( i != -1 ) { fread( SendBuff, SendSize, 1, fp );// SendSizeは4*1024*1024の値を#define while( TotalSend < SendSize ) { TotalSend += send( SendSock, (char *)&SendBuff[TotalSend], SendSize-TotalSend, 0 ); } } printf( "%d/%d\n", i, Q ); } Client //Winsockの設定やファイルのトータルサイズ云々なので略 FILE *fp = fopen( FileName, "ab" ); int Total = 0; for( int i=0 ; i<=Q ; i++ ) { //connect( Sock, (struct sockaddr *)&Addr, sizeof(Addr) ); int Error = FileRecv( Sock, i, Q, R, fp ); if( Error == -1 ) { i--;//エラーが出るのでどこでエラーが出るのか見るために追加 } else { printf( "%d/%d\n", i, Q ); } } int FileRecv( SOCKET Sock, int Flag, int Q, int R, FILE *fp ) { //Winsockの設定をコメントアウト中。外した場合、引数のSOCKET Sockは消す int Total = 0; //フラグ送信 { BYTE buff[4]; memmove( buff, &Flag, 4 ); int Error = send( Sock, (char *)buff, 4, 0 ); if( Error == -1) { return -1; } } if( Flag == Q ){ Buff = new BYTE[R]; memset( Buff, 0, sizeof(Buff) ); while( Total < R ) { Total += recv( Sock, (char *)&Buff[Total], R-Total, 0 ); } fwrite( Buff, R, 1, fp ); delete []Buff; } else { Buff = new BYTE[SendSize]; memset( Buff, 0, sizeof(Buff) ); while( Total < SendSize ) { Total += recv( Sock, (char *)&Buff[Total], SendSize-Total, 0 ); if( Total == -1 ) { delete []Buff; return -1; } } fwrite( Buff, SendSize, 1, fp ); delete []Buff; } // closesocket(Sock); // WSACleanup(); return 1; } 毎回切断してもう一度接続しなおすようにしても(コメントアウトを外す)結果(エラー部)は変わりません。 どこが悪いのか見ていただけないでしょうか?

  • 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の基本仕様を理解していないためと思われます。 ご教示願えれば幸いです。

  • チャットプログラムでの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; }

専門家に質問してみよう