ソケットプログラミング.3
今回は,メッセージのやり取りができるようにしてみます.
d:id:pneumaster:20090523:1243088465で,
accept()の返り値について勘違いしていたみたいです.
man -S 3p socketによると,accept()の返り値は
RETURN VALUE
Upon successful completion, accept() shall return the non-negative file
descriptor of the accepted socket. Otherwise, -1 shall be returned and
errno set to indicate the error.
となっていました.
accepted socketのファイルディスクリプタだそうです.
関数の成功,不成功だけだと思っていました.
ところで,accept()の書式は
int accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len);
だそうですが,第1引数のsocketは
socket Specifies a socket that was created with socket(), has been bound to an address with bind(), and has issued a successful call to listen().
と説明されています.
つまり,accept()の前の関数(listen())を通るのを成功したファイルディスクリプタ
# 前回のソースのsockのことです
と,accept()の返り値のファイルディスクリプタ(以降「s」)は異なるということですか.
う〜む...別にする理由がよく分からないです.
しかも,メッセージ用のファイルディスクリプタを用意するのはサーバ側だけだそうで.
参考にしている本(asin:4274065847)では
と書かれていました.
送るメッセージはこんな感じに流れていくってことなのでしょうか?
(メッセージバッファ)===> s ===> sock ===> (ネット) ===> (クライアントPC)
この問題は置いて,メッセージのやり取りについて進めます.
サーバとクライアントが接続完了したら(accept後),メッセージのやり取りを始めます.
ここではとりあえず,CTRL-CでSIGINTを送るまでメッセージのやり取りを行います.
サーバ側
#define RECV_BUFSIZE 8192 char recv_buf[RECV_BUFSIZE]; while (1) { int i; recv_buf[0] = '\0'; for (i=0; i<RECV_BUFSIZE-1; ++i) { if (recv(s, &recv_buf[i], 1, 0) <= 0) { errsv = errno; strerror(errsv); // NOTE: need to make function or to use `goto' ? // break; return EXIT_FAILURE; } if (recv_buf[i] == '\n') { break; } } recv_buf[i] = '\0'; printf("%s\n", recv_buf); fflush(stdout); }
サーバ側ではrecv()を使って,
用意したメッセージバッファ(recv_buf)に
クライアントから受信するデータを格納することにします.
recv()があるifの条件は0と0以下(-1を想定)で,エラーとしてキャッチしておきます.
# 0はメッセージが受信できなかったときか,
# クライアントが正常に接続を切断した場合になるのだと思います.
# それ以外は,-1だそうです*1.
recv()の第3引数で1文字ずつずつ受信していますが,
RECV_BUFSIZEとしたら,受信できませんでした.
なぜだろう.
クライアント側
#define MESSAGE_BUFSIZE 8192 char send_buf[MESSAGE_BUFSIZE]; /* message buffer */ while (1) { printf("%s> ", ipaddr); fgets(send_buf, MESSAGE_BUFSIZE, stdin); if (send(sock, (char *)send_buf, strlen(send_buf), 0) == -1) { errsv = errno; strerror(errsv); break; } }
fgets()を使って標準入力から,高々MESSAGE_BUFSIZE-1バイトの文字入力させ,
このバッファをsend()します.
ちょっとしたチャットプログラムが完成しました.
今日のソースプログラムはこちら
http://github.com/pneu/chat/tree/fbc11118bb53108179126905ab51015a7a2e3e35
次は複数のクライアントからメッセージを受けられるようにしてみたいと思います.
参考
基礎からわかるTCP/IP ネットワーク実験プログラミング(asin:4274065847)
*1:man -S 3p recv