- 締切済み
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); } }
- みんなの回答 (2)
- 専門家の回答
みんなの回答
- wormhole
- ベストアンサー率28% (1626/5665)
>それではこの列にsend関数をおけば良いのでしょうか? sendをどう置くつもりですか?(どうすればいいかのヒントは先の回答に書いてます) writeを置き換えるという事なら全く変わりませんけど。
- wormhole
- ベストアンサー率28% (1626/5665)
関数read_and_replyでは、メッセージを送信してきたクライアントに対してしか送信してないので、その他のクライアントにはメッセージが送信されないのは当然では?接続しているクライアント全てに送信したいのならacceptしたソケット全てに対して送信しないと。 他、気になった点 ・strncpyは、指定した長さ分コピーした場合にはコピー先に'\0'は付きません。 ・TCPで通信を行う場合、送信(writeなど)1回分が、受信(readなど)1回になるとは限りません。複数回に分割されて受信になる事もありますし複数回の送信が1回で受信されることもあります。
補足
回答ありがとうございます。確認したところ確かにread_and_replyではダメですね。 それではこの列にsend関数をおけば良いのでしょうか?