
現在、複数のクライアントからサーバーにメッセージを送りサーバーからクライアントにメッセージを送るというものを作成しているのですが、クライアントからサーバーにはメッセージを送れるのですが、サーバー側からクライアント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);
}
}
A 回答 (2件)
- 最新から表示
- 回答順に表示
No.2
- 回答日時:
>それではこの列にsend関数をおけば良いのでしょうか?
sendをどう置くつもりですか?(どうすればいいかのヒントは先の回答に書いてます)
writeを置き換えるという事なら全く変わりませんけど。
No.1
- 回答日時:
関数read_and_replyでは、メッセージを送信してきたクライアントに対してしか送信してないので、その他のクライアントにはメッセージが送信されないのは当然では?接続しているクライアント全てに送信したいのならacceptしたソケット全てに対して送信しないと。
他、気になった点
・strncpyは、指定した長さ分コピーした場合にはコピー先に'\0'は付きません。
・TCPで通信を行う場合、送信(writeなど)1回分が、受信(readなど)1回になるとは限りません。複数回に分割されて受信になる事もありますし複数回の送信が1回で受信されることもあります。
この回答への補足
回答ありがとうございます。確認したところ確かにread_and_replyではダメですね。
それではこの列にsend関数をおけば良いのでしょうか?
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
最早開始時間と最遅完了時刻を...
-
C言語 エラーの原因がわからな...
-
std::set<int> で、ある値が何...
-
#define _CRT_SECURE_NO_WARNIN...
-
iTRONプログラミング
-
signal関数の使い方
-
Haskellで関数を合成しようとす...
-
if と配列の組み合わせ
-
C言語 プログラミング
-
「指定されたキャストは有効で...
-
【C++】関数ポインタの使い方
-
複数桁10進数の*桁目だけを抽出...
-
ポストの対応問題
-
信頼区間の1.96や1.65ってどこ...
-
「Aに対するBの割合」と「Aに対...
-
For文の終了値を関数にしても問...
-
配列をnビットシフトする
-
数学 一次関数 関数 y=-3/4x+k(...
-
Enterキーを押されたら次の処理...
-
sscanfとscanfの違いがよくわか...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
#define _CRT_SECURE_NO_WARNIN...
-
「指定されたキャストは有効で...
-
C言語での引数の省略方法
-
【C++】関数ポインタの使い方
-
C言語 エラーの原因がわからな...
-
複数桁10進数の*桁目だけを抽出...
-
return 1L
-
if と配列の組み合わせ
-
ラップ関数とはどんなものですか?
-
式は定数値が必要です」という...
-
数字列を3桁ごとにカンマで区切...
-
実数の整数部,小数部の取得
-
C言語でDxlibを使って3x3の奇数...
-
プログラムについて(UNIX)
-
acceptをalarmでタイムアウトさ...
-
C言語の課題です
-
エラー 添字が付けられた値が、...
-
CStringの配列要素を関数で受け...
-
最早開始時間と最遅完了時刻を...
-
入力された数字を大きい順に並...
おすすめ情報