大学の課題でどぉしても、わからないところがあります。。
システムプログラミングというC言語の授業なんですが、
UDPでチャットを作りなさい。という問題です。
なんとか普通のものはできたのですが、オプション機能を付け加えることが
できません><
分かる方いらしたら、お願いします><
UDPを利用したチャットシステムを作りなさい。
プロトコル
パケットの先頭の一文字はパケットの種類を表す。
C→S S→C 引数
i login 開始 ユーザが入室 ニックネーム
o logout 終了 ユーザが退室 ニックネーム
m message 発言 他のユーザの発言 メッセージ
e error エラー エラー エラーのあった行
すべての通信は行単位で行う。
1文字目は上記のいずれか
2文字目からが引数の内容
サーバの動作
起動時に標準入出力、標準エラー出力は閉じる。停止はシグナルで行う。 SIGINTを受け取ったら、全員に停止メッセージを送って終了する。
i 登録し、入室情報を全員に通知同一ニックネームを使っている場合は(1)のように番号を後につける
o 登録を削除し、退室情報を全員に通知
m メッセージを全員に通知
クライアントの動作
起動時に login プロトコルをサーバに送る
終了時に logout プロトコルをサーバに送る
ユーザがキーボードから入力したメッセージはサーバに送る。行単位で処理。
サーバから送られてきたメッセージは画面に表示
クライアントはこちらです。
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
main(int argc, char *argv[/url]) {
int s;
struct sockaddr_in my_addr, server;
int serverlen, nc;
struct hostent *host;
char buf[1024];
serverlen = sizeof(server);
s = socket(AF_INET, SOCK_DGRAM, 0);
if(s<0) error("socket");
host = gethostbyname(argv[1]);
if(host==NULL) error("gethostbyname");
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(8000);
memcpy(&server.sin_addr, host->h_addr,host->h_length);
fgets(buf, 1023, stdin);
while(buf[0]!='.') {
sendto(s, buf, strlen(buf), 0, (struct sockaddr *)&server, sizeof(server));
memset(buf, 0, 1024);
nc = recvfrom(s, buf, 1023, 0, (struct sockaddr *)&server, &serverlen);
printf("%s", buf);
fgets( buf, 1023, stdin);
}
}
error(char *msg) { perror(msg); exit(1); }
サーバーはこちらです。
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#define BUFMAX 256
#define PORT_NO 8000
char rmsg[10], smsg[BUFMAX];
int sofd;
struct sockaddr_in sv_addr, cl_addr;
error(char *msg) {
fprintf(stderr, "server- "); perror(msg); exit(1);
}
main() {
sofd = socket(AF_INET, SOCK_DGRAM, 0);
if(sofd<0)error("socket");
bzero((char *)&sv_addr, sizeof(sv_addr));
sv_addr.sin_family = AF_INET;
sv_addr.sin_port = htons(PORT_NO);
sv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind (sofd,(struct sockaddr *) &sv_addr, sizeof(sv_addr))<0) error("bind");
servpro();
}
servpro() {
int cc, cadlen, nbyte, i;
char *msg[/url] = { "Hi.\n", "Bye.\n", ".\n", 0};
char buf[1024];
fd_set mask;
struct timeval to;
while(1) { // 無限ループ
FD_ZERO(&mask); //mask をクリア
FD_SET(sofd, &mask); //sofdのマスクをセット
to.tv_sec = 10; //タイムアウトの時間を設定
FD_SET(0, &mask); //標準入力のマスクをセット
if(select(sofd+1, &mask, NULL, NULL, &to)<0)error("select"); // 入力があるまで待つ
if(FD_ISSET(0, &mask)) { // 標準入力の場合
bzero(buf, 1024);
gets(buf);
if(buf[0]=='.') break;
printf("Key board: %s.\n",buf); // 自分に出力
cadlen = sizeof(cl_addr);
cc = recvfrom(sofd, rmsg, 10, 0,(struct sockaddr *) &cl_addr, &cadlen);
if(cc < 0) error("recvfrom");
if(sendto(sofd, buf, strlen(buf), 0,(struct sockaddr *) &cl_addr, cadlen)<0) error("sendto");
sendto(sofd, "\n", 1, 0,(struct sockaddr *) &cl_addr, cadlen);
}
if(FD_ISSET(sofd, &mask)) { // ネットワークから送られてきた場合
cadlen = sizeof(cl_addr);
cc = recvfrom(sofd, rmsg, 10, 0,(struct sockaddr *) &cl_addr, &cadlen);
if(cc < 0) error("recvfrom");
if(sendto(sofd, rmsg, strlen(rmsg), 0,(struct sockaddr *) &cl_addr, cadlen)<0) error("sendto");
/*
for(i=0; msg; i++) {
if(sendto(sofd, msg, strlen(msg), 0,(struct sockaddr *) &cl_addr, cadlen)<0) error("sendto");
}
*/
}
}
}
長くなってすみません><
お願いします><><
お願いします><><
C→S S→C 引数
i login 開始 ユーザが入室 ニックネーム
o logout 終了 ユーザが退室 ニックネーム
m message 発言 他のユーザの発言 メッセージ
e error エラー エラー エラーのあった行
すべての通信は行単位で行う。
1文字目は上記のいずれか
2文字目からが引数の内容
サーバの動作
起動時に標準入出力、標準エラー出力は閉じる。停止はシグナルで行う。 SIGINTを受け取ったら、全員に停止メッセージを送って終了する。
i 登録し、入室情報を全員に通知同一ニックネームを使っている場合は(1)のように番号を後につける
o 登録を削除し、退室情報を全員に通知
m メッセージを全員に通知
クライアントの動作
起動時に login プロトコルをサーバに送る
終了時に logout プロトコルをサーバに送る
ユーザがキーボードから入力したメッセージはサーバに送る。行単位で処理。
サーバから送られてきたメッセージは画面に表示
です><><
i login 開始 ユーザが入室 ニックネーム
o logout 終了 ユーザが退室 ニックネーム
m message 発言 他のユーザの発言 メッセージ
e error エラー エラー エラーのあった行
すべての通信は行単位で行う。
1文字目は上記のいずれか
2文字目からが引数の内容
サーバの動作
起動時に標準入出力、標準エラー出力は閉じる。停止はシグナルで行う。 SIGINTを受け取ったら、全員に停止メッセージを送って終了する。
i 登録し、入室情報を全員に通知同一ニックネームを使っている場合は(1)のように番号を後につける
o 登録を削除し、退室情報を全員に通知
m メッセージを全員に通知
クライアントの動作
起動時に login プロトコルをサーバに送る
終了時に logout プロトコルをサーバに送る
ユーザがキーボードから入力したメッセージはサーバに送る。行単位で処理。
サーバから送られてきたメッセージは画面に表示
です><><
Re:お願いします><><
ソースコードを眺めてみましたが、どうやらUNIX系OS上でのプログラムみたいですね。
要求されている追加項目が複数ありますので、一つずつやっていきましょう。
-サーバ側-
レシーバは既に実装されているので、後は受け取ったメッセージに沿って処理を分けていくだけです。
1.ログイン処理
2.ログアウト処理
3.メッセージをログインメンバー全員に通知
4.SIGINT(Ctrl + Cかな?)を受け取ったらログインメンバー全員に終了することを通知後、終了処理
-クライアント側-
1.起動直後にログイン名を入力させる
2.ログイン情報をサーバへ送信
3.サーバから受信したメッセージを出力
4.終了時にログアウト情報をサーバへ送信
5.クライアントから入力したメッセージをサーバへ送信
大きくまとめましたが、どこでつまづいているのでしょうか?
#Linux環境がないため、当方ではソースコードのコンパイルチェックはしておりません。
要求されている追加項目が複数ありますので、一つずつやっていきましょう。
-サーバ側-
レシーバは既に実装されているので、後は受け取ったメッセージに沿って処理を分けていくだけです。
1.ログイン処理
2.ログアウト処理
3.メッセージをログインメンバー全員に通知
4.SIGINT(Ctrl + Cかな?)を受け取ったらログインメンバー全員に終了することを通知後、終了処理
-クライアント側-
1.起動直後にログイン名を入力させる
2.ログイン情報をサーバへ送信
3.サーバから受信したメッセージを出力
4.終了時にログアウト情報をサーバへ送信
5.クライアントから入力したメッセージをサーバへ送信
大きくまとめましたが、どこでつまづいているのでしょうか?
#Linux環境がないため、当方ではソースコードのコンパイルチェックはしておりません。
お願いします><><
UNIX上なんですかぁ!!??
Windowsで動かしてるはずなんですが><
つまづいてるトコロはまず引数についてでし。
これは処理ごとにメソッドにするのですか?
またログイン情報やログアウト情報をサーバーに送るというのが
どうすればいいか、よくわからないです><
すごい初歩的な質問ですみません。。
お願いします!!!!!!!!!!!!!!!
Windowsで動かしてるはずなんですが><
つまづいてるトコロはまず引数についてでし。
これは処理ごとにメソッドにするのですか?
またログイン情報やログアウト情報をサーバーに送るというのが
どうすればいいか、よくわからないです><
すごい初歩的な質問ですみません。。
お願いします!!!!!!!!!!!!!!!
Re:お願いします><><
送られてきたログイン情報に次のリストのポインタをつけて
管理するといいのではないでしょうか。
サーバー側が決定すればクライアント側は簡単に出来るのではないでしょうか・・多分。
** UDPServer.h **
#define PORTNUMBER
#define TIMEOUT
struct ホストリスト
{
名前
ポート
接続時間
クライアントのアドレス
次のリストのポインタ
}
○○さんようこそといったサーバメッセージ
各関数プロトタイプ宣言
** UDPServer.c **
・main
○○番ポートを空けて待つ
空のホストリスト構造作成
受信処理
if or switchでコマンド処理(i o m e 例外)
・空のホストリスト構造作成
・リストにホスト追加
・リストからホスト削除
・ホスト取得
・受信内容表示
・全てに送信
・個別メッセージ送信
・アイドル状態のホスト削除
管理するといいのではないでしょうか。
サーバー側が決定すればクライアント側は簡単に出来るのではないでしょうか・・多分。
** UDPServer.h **
#define PORTNUMBER
#define TIMEOUT
struct ホストリスト
{
名前
ポート
接続時間
クライアントのアドレス
次のリストのポインタ
}
○○さんようこそといったサーバメッセージ
各関数プロトタイプ宣言
** UDPServer.c **
・main
○○番ポートを空けて待つ
空のホストリスト構造作成
受信処理
if or switchでコマンド処理(i o m e 例外)
・空のホストリスト構造作成
・リストにホスト追加
・リストからホスト削除
・ホスト取得
・受信内容表示
・全てに送信
・個別メッセージ送信
・アイドル状態のホスト削除
お願いします><><
UDPServer.c とUDPServer.h と分けてありますが、これは分けたほうがいいのですか?
ヘッダファイル?はまだよくわからなくて・・・・
もし分けた場合はどのように定義するのでしょうか?
ヘッダファイル?はまだよくわからなくて・・・・
もし分けた場合はどのように定義するのでしょうか?
Re:お願いします><><
>ヘッダファイル?分けたほうがいいの?
今回の内容で、どうしても分ける必要は無いでしょうが。
Cのコンパイラは上から下に向かって解釈していくので、
int main(){
say_hello();
}
void say_hello(){
printf("hello\n");
}
この場合、mainの辺りにくると、say_helloって何?と警告がでる。
長いソースになると全体の見通しが悪くなるので、
プロトタイプ宣言をする事で関数を書く順番を常に意識しなくていい。
void say_hello();
ヘッダファイルに含めるものは、
・マクロの定義(プリプロセッサーの#define)
・構造体、共用体、列挙型の宣言
・typedefの宣言
・外部関数の宣言
・グローバル変数の宣言
との事。
ヘッダファイルでstaticを使うなとかあるようですが、
まだまだ勉強不足です。
今回の内容で、どうしても分ける必要は無いでしょうが。
Cのコンパイラは上から下に向かって解釈していくので、
int main(){
say_hello();
}
void say_hello(){
printf("hello\n");
}
この場合、mainの辺りにくると、say_helloって何?と警告がでる。
長いソースになると全体の見通しが悪くなるので、
プロトタイプ宣言をする事で関数を書く順番を常に意識しなくていい。
void say_hello();
ヘッダファイルに含めるものは、
・マクロの定義(プリプロセッサーの#define)
・構造体、共用体、列挙型の宣言
・typedefの宣言
・外部関数の宣言
・グローバル変数の宣言
との事。
ヘッダファイルでstaticを使うなとかあるようですが、
まだまだ勉強不足です。
Re:お願いします><><
>UNIX上なんですかぁ!!??
>Windowsで動かしてるはずなんですが><
失礼しました。
当方の持っている処理系(VC8)では存在しない標準ヘッダがありましたので
軽くググってlinux版のサンプルで同様のコードがありましたので
勘違いしました。
おそらくgcc系列ではあるのかな?
どちらにしても私はVCしかインストールしていませんのでコンパイルできませんでした。
>Windowsで動かしてるはずなんですが><
失礼しました。
当方の持っている処理系(VC8)では存在しない標準ヘッダがありましたので
軽くググってlinux版のサンプルで同様のコードがありましたので
勘違いしました。
おそらくgcc系列ではあるのかな?
どちらにしても私はVCしかインストールしていませんのでコンパイルできませんでした。