現在、複数のクライアントからサーバーにメッセージを送りサーバーからクライアントにメッセージを送るというものを作成しているのですが、クライアントからサーバーにはメッセージを送れるのですが、サーバー側からクライアント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で質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# leetcode 155 minstack 1 2022/05/07 16:43
- C言語・C++・C# プログラミング c言語 4 2023/03/07 01:05
- C言語・C++・C# バイナリファイルをコピーするのにかかる時間を測りたいのですが実行するとFatel error:gli 2 2022/11/03 01:10
- C言語・C++・C# C言語で再起関数とポインタを用いて文字列反転をする方法がわかりません。 4 2023/04/29 20:32
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- Visual Basic(VBA) Excel-VBAでのファイルの開き方 4 2023/02/14 11:01
- 大学・短大 C言語線形リストの問題です 3 2022/12/22 00:45
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C言語での引数の省略方法
-
「指定されたキャストは有効で...
-
c言語
-
複数桁10進数の*桁目だけを抽出...
-
C言語での奇数の和
-
#define _CRT_SECURE_NO_WARNIN...
-
ラップ関数とはどんなものですか?
-
c言語のリダイレクトによる円...
-
C言語 エラーの原因がわからな...
-
(int *)の意味
-
【C++】関数ポインタの使い方
-
比較回数と交換回数表示について
-
C言語
-
課題でつまってます・・・
-
数字列を3桁ごとにカンマで区切...
-
if と配列の組み合わせ
-
acceptをalarmでタイムアウトさ...
-
市松模様
-
「{ } で囲むだけ」は正しい?
-
実数の整数部,小数部の取得
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
「指定されたキャストは有効で...
-
C言語での引数の省略方法
-
#define _CRT_SECURE_NO_WARNIN...
-
複数桁10進数の*桁目だけを抽出...
-
【C++】関数ポインタの使い方
-
C言語 エラーの原因がわからな...
-
c++でテンプレートのコードでわ...
-
(int *)の意味
-
ラップ関数とはどんなものですか?
-
数字列を3桁ごとにカンマで区切...
-
c言語のリダイレクトによる円...
-
比較回数と交換回数表示について
-
実数の整数部,小数部の取得
-
if と配列の組み合わせ
-
構造体の勉強中です 合計点の高...
-
PowerShellがうまくいかない
-
課題でつまってます・・・
-
c言語の配列を使ってサイコロを...
-
C言語のサイコロシミュレート
-
エラー 添字が付けられた値が、...
おすすめ情報