talkd
Table of Contents
basic socket
前回まで、talkなんていう、プチ時代遅れのアプリを解剖してきた。で、ソケッ ト回りの理解が、おぼつかない事が判明。ならば基本に戻ってソケットの理解 から。この間、本棚から発掘した本のサンプルを試してみる。
sakae@fb:/tmp/src/chap2 $ cc server.c server.c:17:1: warning: type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int [-Wimplicit-int] 17 | main() | ^ | int server.c:34:3: warning: call to undeclared library function 'exit' with type 'void (int) __attribute__((noreturn))'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] 34 | exit(1); | ^ server.c:34:3: note: include the header <stdlib.h> or explicitly provide a declaration for 'exit' server.c:50:2: warning: call to undeclared function 'close'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] 50 | close(soc_waiting); | ^ : 5 warnings generated.
20年前のやつだと、コンパイラーと整合が取れていない。ちゃんと警告を潰し ておく。
#include <unistd.h> #include <stdlib.h>
を追加してからmain回りを改修した。これで現代風になった。
サーバー側の接続用ソケット
(gdb) 39 if(bind(soc_waiting, (struct sockaddr *)&me, sizeof(me)) == -1){ (gdb) p me $2 = { sin_len = 0 '\000', sin_family = 2 '\002', sin_port = 20675, # = 0x50c3 sin_addr = { s_addr = 0 }, sin_zero = "\000\000\000\000\000\000\000" }
ポート番号は、コード上は50000なんで、それを16進数に変換。
(gdb) p/x 50000 $5 = 0xc350
糞石はリトルエンディアンなので、ビッグエンディアンに脳内変換して、それ
を10進数にすると、 sin_port
の番号になる。
下記は、OSの把握する情報
sakae@fb:/tmp/src/chap2 $ netstat -4 Active Internet connections Proto Recv-Q Send-Q Local Address Foreign Address (state) tcp4 0 0 fb.50000 fb.56916 ESTABLISHED tcp4 0 0 fb.56916 fb.50000 ESTABLISHED tcp4 0 96 fb.ssh 192.168.1.5.58448 ESTABLISHED
その時のクライアント側のソケット。
(gdb) p server $2 = { sin_len = 0 '\000', sin_family = 2 '\002', sin_port = 20675, sin_addr = { s_addr = 2231478464 }, sin_zero = "\000\000\000\000\000\000\000" }
クライアント側で、接続情報をどうやって、引き出すか? 下記の様にすれば 良い。
struct sockaddr_in peek; socklen_t plen; connect(soc, (struct sockaddr *)&server, sizeof(server)); getsockname(soc, (struct sockaddr *)&peek, &plen); printf( "getsockname: addr = %s, port = %d\n", inet_ntoa(peek.sin_addr), ntohs(peek.sin_port) );
尚、サーバー側で引き出すには、getpeername を使えとな。
それから、ソケットの大事な特性として、データの流れは双方向で同時に可能 というのがある。全2重通信ね。でも、ソケット番号は一つだ。stdin,stdout の様に方向が決められていないんだ。
n = read(0, buf, BUF_LEN); /* 標準入力0から読む */ write(soc, buf, n); /* ソケットsocに書き出す */ n = read(soc, buf, BUF_LEN); /* ソケットsocから読む */ write(1, buf, n); /* 標準出力1に書き出す */
これ、データのやりとりの一部だけど、同一ディスクリプタsocに対して、 write/readが可能になってる。
もちろん、これを実現する為には、ハード的に信号ラインが2系統になってる。 光ケーブルなら2本のファイバーがセットになっている。書き込み用ラインと 読み込み用ラインね。それ ぞれが一方通行だけど。
光ケーブルと言えば、最近面白い話を聞いた。残念ながらURLは失念しちゃっ たけど、内容はこんな話だ。つい最近、世界最高気温が更新されて60度になっ たそうだ。そこで心配になるのは、光ケーブルの高温障害らしい。温度上昇に より、ケーブルの特性が変化しその結果、エラーが頻発するそうだ。にわかに、 信じられないな。熊谷方面にお住まいの方、報告宜しく。今年の夏は暑いらし いですから。
マシン間の通信
上記は、同一マシン内での出来事だった。同一マシン内なら、わざわざインターネットを利用しな くても、別な方法で可能だ。例えばパイプやそれを発展させた機構が有る。しかし、別マシンのプロ セスと通信しようとしたら、普通は、インターネットを利用する。
そんな事なんで、FreeBSD(fb)をサーバーとし、OpenBSD(ob)の方をクライアン トとして、接続実験。
at fb (server)
sakae@fb:~ $ netstat -4 Active Internet connections Proto Recv-Q Send-Q Local Address Foreign Address (state) tcp4 0 0 fb.50000 ob.28431 ESTABLISHED
ローカルってのは自分のマシンの事。フォリンってのは別なマシンを意味する。 今はfbなマシンで確認してるので、ローカルな所にfbが表われている。そして、 50000は、そのローカルマシン内でプロセス(アプリ)を区別す為に付けられた 識別番号だ。これがインターネット上のアプリを唯一に識別する方法になって いる。尚、OS上からみると、プロセスを識別する為の番号として、プロセス番 号ってのが有るのは、当然の事。何でも番号に置き換えて表現するって言った ら、ユーザーを識別するuidなんてのもある。これなんか、政府がさかんに宣 伝してる、マイナンバーそのものである。
at ob (client)
ob$ netstat -f inet Active Internet connections Proto Recv-Q Send-Q Local Address Foreign Address TCP-State tcp 0 0 ob.28431 fb.50000 ESTABLISHED Active Internet connections Proto Recv-Q Send-Q Local Address Foreign Address udp 0 0 ob.17347 time.cloudflare..ntp udp 0 0 ob.32503 x.ns.gin.ntt.net.ntp :
obなマシンでは、ntpdが動作してるんで、精度の高い時刻サーバーとの接続も、 垣間見られる。
この時のやりとりをパケットキャプチャーしてみた。
ob$ tcpdump -r NOM | cut -b -75 07:03:01.018943 ob.my.domain.28431 > fb.50000: S 2712367259:2712367259(0) w 07:03:01.026564 fb.50000 > ob.my.domain.28431: S 2809207120:2809207120(0) a 07:03:01.026593 ob.my.domain.28431 > fb.50000: . ack 1 win 256 <nop,nop,tim 07:03:23.219277 fb.50000 > ob.my.domain.28431: P 1:11(10) ack 1 win 1027 <n 07:03:23.409477 arp who-has fb tell ob.my.domain 07:03:23.409480 ob.my.domain.28431 > fb.50000: . ack 11 win 256 <nop,nop,ti 07:03:23.526492 arp reply fb is-at 12:34:56:78:9a:bc 07:03:37.691286 ob.my.domain.28431 > fb.50000: P 1:9(8) ack 11 win 256 <nop 07:03:37.736868 fb.50000 > ob.my.domain.28431: . ack 9 win 1027 <nop,nop,ti
クライアントからポート番号が公開されてるサーバーに接続。後はギッタン・ バッタンの交互送信が普通だ。
途中で、珍しいパケット、arpが割り込んできた。これはIPアドレスとイーサ ネット番号との対応を求める要求だ。同一サブネット内では、通信の最下層で、 イーサネット番号(簡単に言うと、NICのシリアル番号)が、利用されているん だ。ボードの交換に供えて、20分間隔ぐらいで、再問い合わせをする事になっ てる。 ボードを交換されちゃうと、シリアル番号が代わる。だから、定期的に最新の 番号に更新してる訳だ。
上で出てきた、プロセス番号とインターネット上でのプロセス識別、IPアド レスとイーサネット番号のように、2重構造で管理してる事が多いぞ。こんが らかるな。
talkd
次は、talkの取次をやってくれる、talkdを調べてみる。ダエモン君なので、 端末を持っていない。だから、今迄の得意技であるgdbを繰り出す訳にはいか ない。困った脳。talkd(8)を見ても、特別なスイッチは用意されていない。
しょうがないので、ソースに当たれ。 /usr/src/libexec/talkd/talkd.c
main(int argc, char *argv[]) { openlog("talkd", LOG_PID, LOG_DAEMON); if (gethostname(hostname, sizeof(hostname)) == -1) { syslog(LOG_ERR, "gethostname: %m"); _exit(1); } : if (argc > 1 && strcmp(argv[1], "-d") == 0) debug = 1;
ダエモン君と言ってもmainが有ってホッとする。物の本の説明では、inetdが ネットワークの総合受付を担当し、該当するダエモン君にパケットを転送して くれるそうだ。そして、パケットは、ソケット番号を0として渡すという規約があるらし い。ここら辺の事情は昔盛んにやったcgiと一緒だな(と、遠い昔を懐かしんで おります。今の人にcgiなんて言っても通じないだろうけど)。とほほのCGI入門
それはそうと、-dと言うオプションを付けて起動されると、debugフラグがon になり、print文が自動的に活性化されるって、読める。
ob$ grep ntalkd /etc/inetd.conf ntalk dgram udp wait root /usr/libexec/ntalkd ntalkd -d
でも、端末は無い。どこに出力する? それはsyslogファイルに出力される。 その為の仕掛けが、openlogの宣言みたい。これを最初に実行しておくと、出 力先が、syslogになる。
setup syslog
syslogを扱かうのは、syslogdと言う、これまたダエモン君だ。彼はOS起動時 から常駐している。で、syslogdの使い方を勉強すると言う、泥縄式、かっこ 良く言うと、オンデマンドな勉強ね。
どう制御するかは、/etc/syslog.confに設定しておけと。
talkdの中で、どの様に使われているか、調べて、syslog.confに反映って流れ。 職人さんみたいに、見て技を盗めってことだ。
table.c
if (debug) syslog(LOG_DEBUG, "find_match: not found"); if (debug) print_request("find_request", request);
これが2つの利用方法。
print_request(char *cp, CTL_MSG *mp) { : syslog(LOG_DEBUG, "%s: %s: id %d, l_user %s, r_user %s, r_tty %s", cp, tp, mp->id_num, mp->l_name, mp->r_name, mp->r_tty);
print_request
は、ラッパーになっている。
cron.info /var/cron/log daemon.info /var/log/daemon daemon.debug /var/log/daemon ## add ftp.info /var/log/xferlog
cron/daemon/ftpとかの大枠と、情報の重要性(emarg/err/crit/info/debug)の 組み合わせで、どのファイルに出力するか決定してるようだ。
今回は、daemonに出力する様に、一行追加。そして、syslogdを再起動して、 設定を有効にする。
なお、これらのログファイルは、cronから起動されるnewsyslogコマンドの対 象になっている。独自のファイルに出力したい場合は、この事も考慮したら安 心だ。
real communication
準備万端整ったので、talkしてみる。
ob$ ps awx | grep talk 39953 ?? Sp 0:00.00 ntalkd -d 43082 p2 I+p 0:00.01 talk joy@fb
ダエモン君が起動してるな。彼は端末から切り離されているんで、端末欄が?? になっている。
ob$ netstat -f inet Active Internet connections Proto Recv-Q Send-Q Local Address Foreign Address TCP-State tcp 0 0 ob.21886 fb.31636 ESTABLISHED
こちらは、FreeBSD側。ちとOpenBSDとは趣きが違う。
sakae@fb:~ $ ps awx | grep talk 968 u0 I+ 0:00.08 talk: (talk)
sakae@fb:~ $ netstat -4 Active Internet connections Proto Recv-Q Send-Q Local Address Foreign Address (state) tcp4 0 0 fb.31636 ob.21886 ESTABLISHED udp4 0 0 fb.63500 *.*
そして、肝心のdebugログ相当。
/var/log/daemon
Mar 24 08:44:26 ob talkd[39953]: process_request: look_up: id 0, l_user joy, r_user sakae, r_tty Mar 24 08:44:26 ob talkd[39953]: find_match: look_up: id 0, l_user joy, r_user sakae, r_tty Mar 24 08:44:26 ob talkd[39953]: find_match: not found Mar 24 08:44:26 ob talkd[39953]: process_request: look_up: not_here, id 0 Mar 24 08:44:26 ob talkd[39953]: process_request: announce: id -1, l_user joy, r_user sakae, r_tty Mar 24 08:44:26 ob talkd[39953]: find_request: announce: id -1, l_user joy, r_user sakae, r_tty ttyp0 Mar 24 08:44:26 ob talkd[39953]: insert_table: announce: id -1, l_user joy, r_user sakae, r_tty ttyp0 Mar 24 08:44:26 ob talkd[39953]: process_request: announce: success, id 1 Mar 24 08:44:44 ob talkd[39953]: process_request: delete: id 1, l_user joy, r_user sakae, r_tty Mar 24 08:44:44 ob talkd[39953]: delete_invite(1) Mar 24 08:44:44 ob talkd[39953]: delete: announce: id 1, l_user joy, r_user sakae, r_tty ttyp0 Mar 24 08:44:44 ob talkd[39953]: process_request: delete: success, id 0
check code
syslogの結果とコードをつき合わせてみる。忘れないうちに、目についた所を。
cc = recvfrom(STDIN_FILENO, (char *)&request, sizeof(request), 0, (struct sockaddr *)&response.addr, &len); : cc = sendto(STDOUT_FILENO, (char *)&response, sizeof(response), 0, &ctl_addr, sizeof(ctl_addr));
メインのループの中で、パケットの送受部分。 規約では0だけで賄うという説明だったんだけど、、
ob$ cd /usr/include/ ob$ grep STDIN_FILENO * | grep define unistd.h:#define STDIN_FILENO 0 /* standard input file descriptor */
STDOUT_FILENO
は、1 となってた。その方が、ずっと馴染があるからね。前言
撤回の、あの人みたい。
process.c
process_request(CTL_MSG *mp, CTL_RESPONSE *rp){ if (debug) print_request("process_request", mp); switch (mp->type) { case ANNOUNCE: case LEAVE_INVITE: case LOOK_UP: case DELETE: default: if (debug) print_response("process_request", rp);
こんな風に、要求によってディスパッチしてる。入口と出口のパケットを、それ ぞれsyslogしてるんだけど、その表題が同名だ。まぎらわしいと思えるぞ。そ れとも、詳細内容が違うから、それで判別しろってか? ちょいとの工夫で、 もっと良くなると思うぞ。ちなみに、
print_request(char *cp, CTL_MSG *mp) syslog(LOG_DEBUG, "%s: %s: id %d, l_user %s, r_user %s, r_tty %s", cp, tp, mp->id_num, mp->l_name, mp->r_name, mp->r_tty); print_response(char *cp, CTL_RESPONSE *rp) syslog(LOG_DEBUG, "%s: %s: %s, id %d", cp, tp, ap, ntohl(rp->id_num));
こんな感じだ。
ひとつ追ってみる。process.c
case LEAVE_INVITE: ptr = find_request(mp); if (ptr != NULL) { rp->id_num = htonl(ptr->id_num); rp->answer = SUCCESS; } else insert_table(mp, rp);
招待する所。
table.c
find_request(CTL_MSG *request) if (debug) print_request("find_request", request); return (NULL); insert_table(CTL_MSG *request, CTL_RESPONSE *response) if (debug) print_request( "insert_table", request );
テーブル(リンク・リスト)に登録されていないか確認して、未登録なら登録。 これ2重登録の防止を図っている。
struct table_entry { CTL_MSG request; time_t time; TAILQ_ENTRY(table_entry) list; }; TAILQ_HEAD(, table_entry) table;
テーブルは、こんな風。登録時刻をエレメントに保持してるのは、メッセージ の繰り返しを防ぐため。有効時間が60秒に設定されてて、それを越えると、エ ントリーが削除される。
Noto
前回だったか、wiresharkを入れた時、メニューが豆腐だった。それで適当な フォントを入れて回避した。そんじゃ、ブラウザーの一つでも入れておこうと 思ったんだ。firefoxでもと入れようとしたら、i386はサポート外だった。 それじゃ、chrome でもとなった。無事に導入できた。
Notoなんて言うフォントを引き連れてきたぞ。なんじゃいこれ? 能登のロー カル・フォントかいな? さざ波とか東雲みたいに、ユニークな名前のフォントが多いですから。一応調 べておくか。
/ports/fonts/noto
Noto is a font family designed to cover the entire range of the Unicode standard. When text is rendered by a computer, sometimes characters are displayed as "tofu". They are little boxes to indicate your device doesn't have a font to display the text. Google has been developing a font family called Noto, which aims to support all languages with a harmonious look and feel. Noto is Google's answer to tofu. The name noto is to convey the idea that Google's goal is to see "no more tofu". Noto has multiple styles and weights, and freely available to all.
Googleの豆腐文字撲滅作戦の成果ですとな。納得しましたです。豆腐文字も国 際的になったものだな。
ChatGPT
Q: 光ファイバーが温度障害で、通信エラーを起こす事があるって話を聞きま した。本当ですか? 事例があったら教えてください。
A: 光ファイバーが温度によって通信エラーを起こす可能性はありますが、一般的には正しく設計された光ファイバーネットワークではそれが起こることは稀です。光ファイバーケーブルは一般的に温度変化に対して比較的安定していますが、極端な温度変化や不適切な設置などの要因によって問題が生じることがあります。
例えば、以下のような事例が報告されています:
- 極端な温度変化による影響: 光ファイバーケーブルが急激な温度変化にさらされると、光ファイバー自体や接続部分の物理的な変形が起こる可能性があります。これは光の伝送特性に影響を与え、通信エラーを引き起こす可能性があります。
- 熱膨張による問題: 温度変化によってケーブルや接続部分が膨張・収縮することがあり、これが光ファイバーの位置や方向を微妙に変化させることがあります。これにより、光の伝送経路が変わり、通信エラーが発生する可能性があります。
- 熱による信号劣化: 温度上昇によって光ファイバー内の材料が劣化することがあり、光の伝送特性が損なわれる場合があります。これにより、信号の品質が低下し、通信エラーが生じる可能性があります。
これらの問題を避けるためには、適切な光ファイバーの設計、適切な保護、適 切な温度管理が重要です。例えば、温度変化の激しい環境では、特に耐熱性の あるケーブルや適切な冷却装置を使用することが重要です。また、光ファイバー の設置や保守において、温度変化が問題となる可能性を考慮し、適切な対策を 講じることが重要です。
Q: 光の伝送特性と温度って関係あるのですか? 温度によって、伝送スピード が変わるとか、屈折率が変化するとかあるのでしょうか? 材料は石英ガラス ですよね。それとも最近は、プラスティック製が多いのかな?
A: 光ファイバーの伝送特性には、温度の影響があります。光ファイバーは一般的に石英ガラスから作られていますが、一部の応用ではプラスティック製の光ファイバーも使用されることがあります。
温度が変化すると、光ファイバー内の材料(主に石英ガラス)の屈折率が微妙に変化することがあります。この屈折率の変化は、光の伝送速度に影響を与える可能性があります。一般的に、温度が上昇すると光ファイバー内の材料の屈折率が低下し、光の速度が速くなる傾向があります。逆に、温度が下がると光の速度が遅くなる傾向があります。
このような温度による屈折率の変化は、光信号が光ファイバーを伝播する際に時間遅れや位相のずれを引き起こす可能性があります。特に高精度や高速の通信システムでは、温度変化が信号の品質に影響を与えることがあります。
プラスチック製の光ファイバーは一般的に石英ガラス製のものよりも柔軟性があり、特定のアプリケーションに適していますが、熱や温度変化には敏感です。そのため、プラスチック製の光ファイバーを使用する場合は、温度管理がより重要になります。
総じて言えることは、温度変化が光ファイバーの伝送特性に影響を与える可能 性があるため、設計や運用段階でこの点を考慮する必要があるということです。
Q: 光ファイバー温度計って、有りそうと思いますが、いかがでしょう?
A: 光ファイバー温度計の開発や利用は、光ファイバーネットワークの管理や保守において有益である可能性があります。光ファイバーネットワークにおける温度のモニタリングは、以下のような利点が考えられます:
- ネットワークの安定性向上: 温度変化が通信エラーを引き起こす可能性があるため、温度を定期的にモニタリングすることで、問題が発生する前に予防措置を講じることができます。これにより、ネットワークの安定性や信頼性が向上します。
- 故障の早期発見: 温度計を使用することで、異常な温度上昇や急激な温度変化を検出し、ポテンシャルな故障の早期発見につなげることができます。これにより、ネットワークのメンテナンスや修復を迅速に行うことが可能になります。
- 設備の効率化: 温度データを収集し、光ファイバーネットワークの設備の動作状況を評価することで、効率的な運用やリソースの最適化が可能になります。例えば、冷却装置の制御や設置場所の最適化などが考えられます。
- 品質管理の向上: 温度計を使用して温度データを記録・分析することで、ネットワークの品質管理を向上させることができます。温度に関連する問題を特定し、改善策を検討することで、ネットワーク全体のパフォーマンスを向上させることができます。
以上のような利点があるため、光ファイバーネットワークの運用管理において、 光ファイバー温度計の導入は有益であると考えられます。これにより、ネット ワークの安定性や信頼性の向上、故障の早期発見、設備の効率化、品質管理の 向上などのメリットが得られるでしょう。
質問者に、よいしょしてないか、自力で確認。
本当に有った。ビックリですよ。