ネットワークプログラムの方法の初歩について説明します。
ネットワークプログラムには、コネクション型とコネクションレス型がありますが、ここでは、コネクション型を利用します。
通信をする場合、データを提供する側のコンピュータをサーバといい、データを参照する側のコンピュータをクライアントと呼びます。
Hello サーバという、クライアントから接続されると "Hello world." を出力するサーバと、Hello サーバに接続し出力された文字列を表示するクライアントを作成してみます。
socket 関数は、ネットワーク上でデータをやりとりする時に必要な領域の確保を行います。
socket 関数で取得した領域は、close 関数で開放できます。
サーバのbind, listen, accept 関数は、セットで、クライアントからの受信を可能にします。
クライアントのconnect 関数によって、セッションが確立し、データの送受信が可能となります。
終了時は、shutdown 関数を、サーバとクライアントの両方から発行することで終了します。
クライアントAP サーバAP (hellocl) (hellosv) socket sid1 bind sid1 listen accept sid2 socket sid connect sid → ..... recv sid send sid2 → ..... recv sid ← send sid2 ..... shutdown sid → ← shutdown sid2 close sid close sid2 close sid1 |
Hello サーバという、クライアントから接続されると "Hello world." を出力するサーバのソース(hellosv.c, hellosv.pl)と、Hello サーバに接続し出力された文字列を表示するクライアントのソース(hellocl.c, hellocl.pl)です。
C言語版は、make コマンドにより、メイクすることができます。
プログラムの種類 | C言語版 | Perl版 | telnet |
---|---|---|---|
サーバプログラム | hellosv.c | hellosv.pl | |
クライアントプログラム | hellocl.c | hellocl.pl | telnet ホスト名 5001 |
メイクファイル | makefile |
サーバで、Hello サーバを起動した後、クライアントから接続すると、何回でも、Hello world. を表示します。
サーバプログラムは、delキーや、Ctrl+Cなどで終了します。
Perl版のプログラムは、拡張子に.plが付きます。
クライアントプログラムの代わりに、標準のtelnetコマンドを使うこともできます。
サーバとクライアントのプログラムの組み合わせは自由です。
サーバとクライアントにそれぞれのプログラムを転送 srv01# rcp hellocl srv02:. サーバプログラムの起動 srv01# hellosv srv01 クライアントプログラムの起動 srv02# hellocl srv01 Hello world. クライアントにtelnetプログラムを利用 srv02# telnet srv01 5001 Trying 10.0.1.1... Connected to srv01. Escape character is '^]'. Hello world. Connection closed by foreign host. |
実際に、ネットワークを流れるデータを見てみましょう。
セッションの接続から、"Hello world."のデータ送信の状況を見てみます。
通信データのダンプには、tcpdump などのツールを使用します。
通信データには、TCPヘッダ、IPヘッダ、イーサネットヘッダが付加されます。
IPヘッダにはIPアドレスなどの情報があり、通信相手のホストを識別します。
また、TCPヘッダには、ポート番号などの情報があり、通神相手のプログラムを識別します。
通信データのフォーマットは、以下のような内容です。
[ Ether header (14) ] [ - - IP header (20) - - ] [ TCP header (20) - - ] [ data ] [ to MAC addr ] [ from MAC addr ] [typ] Vh Ts [siz] [flagment ] Tl Pn [sum] [ to addr ] [from addr] [toP] [frP] [ SEQ no ] [ ACK no ] Of Fg [wsz] [sum] [ugp] [ option ] [dat] 00 00 4c 11 99 75 00 00 4c 11 c4 30 08 00 45 00 00 2c 81 b2 00 00 1e 06 d1 dc 85 d0 1e c9 85 d0 1e d4 09 f8 13 89 60 a1 4e 01 00 00 00 00 60 02 40 00 44 79 00 00 02 04 04 00 82 4c |
通信データの各ヘッダ情報の内容は、以下のような内容が格納されています。
===イーサネットヘッダ情報=== MAC address[5]: MACアドレス 00004c119975: ハードウェアメーカ毎に設定 00004c11c430: ハードウェアメーカ毎に設定 Ethernet type[2]: イーサネットタイプ 0800: IP 0806: ARP ===IPヘッダ情報=== IP Version / Header size[1]: IPバージョン/ヘッダサイズ 4: バージョン4 5: 20byte (5*4) TOS (type of service)[1]: サービス種別 00: Total IP size[2]: IPパケットのトータル長 002c: 44byte (0x2c) Flagment[4]: IPパケット分割情報 81b20000: TTL (time of live)[1]: IPパケットの寿命 1e: 30秒 (0x1e) Protocol number[1]: IPプロトコル番号 01: ICMP 06: TCP 11: UDP Check sum[2]: IPヘッダのチェックサム d1dc: IP address[4]: IPアドレス 85d01ed4: srv01(例の場合) 85d01ec9: srv02(例の場合) ===TCPへッダ情報=== Prot no[2]: ポート番号 0014: port 20 (ftp-data) 0015: port 21 (ftp) 0017: port 23 (telnet) 0050: port 80 (http) 09f8: port 2552 (例の場合:サーバ->クライアント) 1389: port 5001 (例の場合:クライアント->サーバ) SEQ no[4]: シーケンス番号 60a14e01: ACK no[4]: 応答確認番号 00000000: Offset[1]: データオフセット 6: 24byte (6*4) 0: Flag[1]: フラグ 01: FIN フィンビット (FINish) TCPコネクションのshutdown時、切断を要求 02: SYN シンクロビット (SYNc) TCPコネクションのconnect時、最初のパケットに付加 04: RST リセットビット(ReSeT) データ転送のキャンセルなど、コネクションの強制切断を要求 08: PSH プッシュビット (PuSH) データ通信時バッファリングせずに転送 10: ACK 応答ビット(ACKnowledge) ほとんどのパケットに付加される応答確認フラグ 20: URG 緊急ビット(URGent) |
通信データのパケットの種類と、TCP ソケット状態の遷移と通信データの流れの関係です。
TCP/IPでは、コネクションを確立するために、SYNフラグ付きのパケットを送り、ACK SYNフラグ付きのパケットを受け取り、ACKフラグ付きのパケットを送ります。このように、フラグ付きのデータを3回やりとりするため、3WAYハンドシェイクと呼んでいます。
クライアントAP サーバAP (hellocl) (hellosv) socket sid1 bind sid1 listen [LISTEN] accept sid2 socket sid connect sid →SYN [SYN_SENT] ACK SYN← [SYN_RECEIVED] →ACK [ESTABLISHD] [ESTABLISHD] ..... recv sid2 send sid →ACK PUSH ACK← ..... recv sid ACK PUSH← send sid2 →ACK ..... shutdown sid →FIN [CLOSE_WAIT] [FIN_WAIT_1] ACK FIN← shutdown sid2 [FIN_WAIT_2] →ACK [LAST_ACK] [TIME_WAIT] close sid close sid2 close sid1 |
TCP ソケットの状態には次のようなものがあります。
netstat コマンドで、TCP ソケットの状態を参照することができます。
セッションが確立している場合は、ESTABLISHEDと表示されます。