目的 ネットワークプログラミング: UDP TCP/IPの基礎の理解 ソケットプログラミングの基礎の理解 CS-24 太田 能 どうやってプロセス間通信を実現するのか? コネクションレスレス型ソケットプログラミングの理解 注)コネクション型ソケットプログラミングは2で学習 ネットワークの構成要素 ホスト ルータ リンク:LAN/MAN/WAN TCP/IPの基礎 LAN ルータ LAN/MAN/WAN LAN LAN ホスト TCP/IPプロトコルスタック IPC (Inter Process Communication) 受信ホストまでデータが届く 特定のプロセスにデータ渡される プロセス プロセス プロトコル:規則,手順,規格 IP層:データをホストまで届ける機能 TCP/UDP層:データをプロセスまで届ける機能 ホストインタフェース識別:IPアドレス プロセス識別:ポート番号 プロセス プロセス ルータ LAN ホスト アプリケーション層 各種アプリケーション プロセス プロセス プロセス プロセス プロセス プロセス プロセス プロセス LAN/MAN/WAN LAN ホスト アプリケーション層 プロセス間通信 LAN ホスト ソフトウェア設計及び実験:ネットワークプ ログラミング1 エンドホスト間転送 隣接ホスト間通信 TCP UDP IP LAN/WAN ルータ IP TCP UDP IP LAN/WAN 1 クライアント・サーバモデル ソケット・ポート番号・IPアドレスの関係 送信ホスト 受信ホスト アプリケーション層 プロセス アプリケーション層 プロセス ソケット 6 ポート 1032 TCP UDP ソケット 4 ポート 25 ソケット記述子:プロセス側の通信端点識別子 ポート番号:トランスポート層側の通信端点識別子 IPアドレス:ホストのインタフェース識別子 プロセスはソケットに対し読み書きすることで通信を実現 IPアドレス ルータ IP IP 192.168.1.2 192.168.1.1 192.168.5.1 LAN/MAN/WAN 192.168.1.0 TCP UDP IP 192.168.5.2 LAN/MAN/WAN 192.168.5.1 送信ホスト内でのメッセージの流れ 送信ホスト プロセスはソケットにメッセージを書込む アプリケーション層 プロセス メッセージ ソケット 6 送信元ポート ポート 宛先ポート 1032 セグメント 送信元IPアドレス TCP 1032;25 宛先IPアドレス UDP ルータ IPデータグラム 192.168.1.2;192.168.5.2 IP IP 192.168.1.2 192.168.1.1 192.168.5.1 LAN/MAN/WAN 192.168.1.0 ソケット 6 ポート 1032 TCP UDP IP 192.168.1.2 プロセス プロセス リクエスト ①サーバのIPアドレスとポート番号は既知でなければならない ⇒サーバのポート番号を事前に決め,クライアントに知らせておく必要有 レスポンス ②リクエストからクライアントのIPアドレスとポート番号は分かる ⇒クライアントのポート番号はシステムが適当に決めても可 ソケット ソケット 4 ②自動割当の場合が多い 6 ポート ポート ①明示的割当必須 25 1032 TCP 実際のデータの流れ TCP UDP UDP ルータ IP IP IP LAN/MAN/WAN LAN/MAN/WAN ルータ内でのメッセージの流れ 受信ホスト アプリケーション層 プロセス アプリケーション層 プロセス アプリケーション層 プロセス ソケット 4 ポート 25 ソケット 4 ポート ルータは経路制御により適切な経路にフォワード 25 ソケット 6 ポート 1032 TCP UDP TCP UDP IP 192.168.5.2 IP 192.168.1.2 受信ホスト アプリケーション層 プロセス メッセージ ソケット 4 ポート 25 セグメント TCP 1032;25 UDP ルータ IPデータグラム 192.168.1.2;192.168.5.2 IP IP 192.168.5.2 192.168.1.1 192.168.5.1 プロセスはソケットからメッセージを読込む LAN/MAN/WAN 192.168.1.0 サーバ アプリケーション層 送信ホスト 受信ホスト内でのメッセージの流れ アプリケーション層 プロセス クライアント:サービスを受ける側 サーバ :サービスを提供する側 受信ホスト LAN/MAN/WAN 192.168.5.1 送信ホスト クライアント アプリケーション層 LAN/MAN/WAN 192.168.5.1 ソフトウェア設計及び実験:ネットワークプ ログラミング1 TCP IPデータグラム UDP 192.168.1.2;192.168.5.2 ルータ IP 192.168.1.1 192.168.5.1 LAN/MAN/WAN 192.168.1.0 IP 192.168.5.2 LAN/MAN/WAN 192.168.5.1 TCPセグメントフォーマット 2Bytes 送信元ポート 宛先ポート シーケンス番号 応答確認番号 u a p r s f r c s s y i ヘッダ長 予約 ウィンドウ g k h t n n チェックサム 緊急ポインタ オプション,パッディング ヘッダ メッセージデータ 可変長 2 UDPデータグラムフォーマット ポート番号 (1/2) 目的 長さ プロセスを識別するために使用 2Bytes 送信元ポート セグメント長 ヘッダ 宛先ポート チェックサム メッセージデータ 可変長 ポート番号 (2/2) ポート番号 ウェルノウン (Well-known) ポート 256〜1023 予約済み(スーパーユーザプロセスが使用) 1024〜5000 自動割当範囲(パッシブオープン時に割当) 5001〜65535 ユーザが自由に利用可能な範囲 IP datagram(v4) のフォーマット 20-65535bytes 20-60bytes 有名なプロセスが使用 例)ftp = 21, telnet = 25 プロセス名との対応 /etc/services の参照 getservbyname() により可能 途 用 0〜255 ウェルノウンポート 2バイト (0〜65535) ヘッダ バージョン 4bits ヘッダ長 4bits データ Type of Service 4bits Time To Live:8bits Total length: 16bits Flags 3bits Identification:16bits Protocol:8bits Fragmentation offset:13bits Header checksum:16bits 送信元 IP アドレス: 32bits 目的 IP アドレス: 32bits オプション IPアドレス 目的 ホスト・ルータのインタフェース識別 論理アドレス 長さ:4バイト(Ver.4) [16バイト(Ver.6)] ビット表現:10010110 00111011 00100110 11000101 ドット表現:150.59.38.197 トランスポートプロトコル DNS (Domain Name Service) サーバへの問合せ /etc/hosts の参照により解決 getservbyname()関数から名前解決 TCP(Transmission Control Protocol) コネクション型 バイトストリーム型 UDP(User Datagram Protocol) コネクションレス型 非バイトストリーム型 FQDN表現:tama.is.tokushima-u.ac.jp Fully Qualified Domain Name ソフトウェア設計及び実験:ネットワークプ ログラミング1 3 TCPによるコネクション通信の実現 送信ホスト アプリケーション層 プロセス TCP コネクション型 信頼性の高いエンド間通信を実現 IP層における低信頼性をカバー オーバヘッド大⇒リアルタイム通信には不適 受信ホスト アプリケーション層 ①パッシブオープン(サーバ) ③データ送受信用ソケット 受付ソケットの生成 ②アクティブオープン(クライアント) メッセージ プロセス ①受付用ソケット メッセージ ②自動割当 コネクション確立要求 ポート番号はTCPが自動割当 ソケット ソケット ソケット ③コネクション確立応答(サーバ) 5 4 6 メッセージ送受信用ソケット生成 ポート ポート ④データ転送(クライアント・サーバ) 25 1032 メッセージ送受信用ソケットを利用 スリーウェイハンドシェイク s;1032;25 ② バイトストリーム型 ③ 1032;25;s,a 受信ホストでメッセージの境界が見えない 1032;25 ④ TCP IP TCPによる高信頼通信の実現 受信ホスト 時間 ルータ LAN/MAN/WAN IP TCP 時間 IP LAN/MAN/WAN TCPによるバイトストリームの実現 アプリケーション層 損失メッセージを補償する プロセス ab cd ef ab ソケット 信頼性高い 6 処理が重く低速 ポート fe 1032;25 1032 誤り制御・順序制御 dc 1032;25 アプリケーション層 プロセス ef cd ソケット 5 ポート ba 1032;25 25 dc 1032;25 受信ホスト 送信ホスト:メッセージを分けて送信 アプリケーション層 受信ホスト:受信メッセージをまとめて読出し アプリケーション層 プロセス プロセス ab cd abcd ソケット ソケット 5 6 受信側でメッセージの境界が見えない ポート ポート 25 1032 dc 1032;25 ba 1032;25 1032;25 TCP ba UDP fe 1032;25 UDP TCP 1032;25 TCP ba UDP 送信ホスト ba 1032;25 192.168.1.2;192.168.5.2 IP IP IP dc 1032;25メッセージ損失 192.168.1.2;192.168.5.2 ②損失メッセージの再送 192.168.5.2 192.168.1.2 fe 1032;25 192.168.1.2;192.168.5.2 LAN/MAN/WAN LAN/MAN/WAN 192.168.1.0 192.168.5.1 ①再送要求 UDP コネクションレス型 コネクション設定不要 低信頼性 オーバヘッド小 ⇒管理アプリケーション,リアルタイム通信に適 必要ならば上位レイヤで保証 非バイトストリーム型 受信ホストでメッセージの境界が見える 送信ホスト IP 192.168.1.2 dc 1032;25 UDP TCP ルータ IP 192.168.1.1 192.168.5.1 LAN/MAN/WAN 192.168.1.0 LAN/MAN/WAN 192.168.5.1 UDPによる非バイトストリームの実現 受信ホスト 送信ホスト:メッセージを分けて送信 アプリケーション層 受信ホスト:受信メッセージを分けて読出し アプリケーション層 プロセス プロセス ab cd ab cd ソケット ソケット 4 6 受信側でメッセージの境界が見える ポート ポート 13 1032 dc 1032;13 ba 1032;13 送信ホスト 1032;13 TCP ba UDP IP 192.168.1.2 dc 1032;13 UDP TCP ルータ IP 192.168.1.1 192.168.5.1 LAN/MAN/WAN 192.168.1.0 ソフトウェア設計及び実験:ネットワークプ ログラミング1 IP 192.168.5.2 IP 192.168.5.2 LAN/MAN/WAN 192.168.5.1 4 UDPによるコネクションレス通信の実現 受信ホスト 送信ホスト アプリケーション層 プロセス cd ef ソケット 4 ba 1032;13 ポート 13 dc 1032;13 アプリケーション層 損失メッセージを補償しない プロセス ab cd ef ab ソケット 信頼性低い 6 処理が軽く高速 ポート fe 1032;13 1032 メッセージ損失検知不可能 dc 1032;13 そのまま上位層に渡す 1032;13 TCP ba UDP × ソケットプログラミングの基礎 × fe 1032;13 UDP TCP ba 1032;13 192.168.1.2;192.168.5.2 IP IP dc 1032;13 192.168.1.2;192.168.5.2 メッセージ損失 192.168.5.2 fe 1032;13 192.168.1.2;192.168.5.2 LAN/MAN/WAN LAN/MAN/WAN 192.168.1.0 192.168.5.1 IP API(Application Programming Interface) カーネルに実装された機能へのインタフェース 関数やシステムコールにより提供 TCP/IP利用の場合⇒ソケット関数,TLI関数など アプリケーション層 プロセス プロセス プロセス プロセス プロセス プロセス データ転送 ソケット関数/TLI関数 TCP ソケットシステムコール一覧 機能 ソケット作成 ソケットに名前設定 接続受付準備 接続要求 接続受付 UDP ソケットのクローズ IP その他 LAN/WAN gethostbyname関数(1/3)[pp.120-121,124] ネットワークバイトオーダー ホストにより複数バイトデータの内部表現異なる 例) 3000 = 0x0bb8 (2バイトデータ) リトルエンディアン方式 ビッグエンディアン方式 (インテル80x86等のCPU) (モトローラ680x0等のCPU) アドレス b8 0b n n+1 アドレス 関数名 socket bind listen connect accept read, write, recv, send recvfrom, sendto shutdown, close ioctrl, socketpair, setsocketopt, getsockopt, getsockname, getpeername #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> 0b b8 struct n n+1 戻り値 成功時…ホスト情報を格納するhostent 構造体へのポインタ エラー…−1 char *name; ホスト名が格納されている文字列への ポインタ 通信の際のデータの並びを統一する必要あり TCP/IPのプロトコルヘッダはビッグエンディアンで処理 htonl();整数(long)をホスト形式からネットワーク形式に変換 htons();整数(short) 〃 〃 〃 など(pp.114-115) ソフトウェア設計及び実験:ネットワークプ ログラミング1 hostent* gethostbyname(char *name); 5 gethostbyname関数(2/3)[pp.120-121,124] struct char char int int char } #define hostent{ *h_name; /* ホストの正式名称 */ **h_aliases; /* 別名リスト */ h_addrtype; /* アドレスタイプ(AF_INET)*/ h_length; /*アドレス長(v.4では4バイト)*/ **h_addr_list; /* アドレスのリスト */ gethostbyname関数(3/3)[pp.120-121,124] shost = gethostbyname(”tama.is.tokushima-u.ac.jp”); ホストの正式名称 tama.is.tokushima-u.ac.jp short = ・ h_name=・ h_aliases=・ ホストの別名リスト もしあれば h_addrtype = 構造体の在処 (アドレス)を格納 したポインタ変数 AF_INET h_length = 4 h_addr_list=・ : h_addr (=h_addr_list[0]) アドレスリスト 150 59 38 197 もしあれば h_addr h_addr_list[0] /* アドレス(下位互換性保持のため) */ : tama.is.tokushima-u.ac.jpの調査結果を格納した構造体 UDPソケットプログラミングの流れ クライアント サーバ アプリケーション層 両方とも同様な流れ アプリケーション層 サーバのポート番号は プロセス プロセス 明示的割付必要 準備 準備 ①socket(); ソケット生成 ①socket(); ②bind(); 情報割付 ②bind(); 送受信(③④繰返し) 送受信(③④繰返し) UDPプログラミング ③sendto(); 相手(IP+ポート)へ送信 ③recvfrom(); ④recvfrom();相手(IP+ポート)から受信 ④sendto(); 終了 終了 ⑤close(); ソケットクローズ ⑤close(); sockaddr_in構造体 ソケット ソケット ①⑤ アドレスファミリー 自動割当可 6 5 明示的割付 ポート番号 ポート ② ポート 1032 13 UDP UDP IPアドレス IP socket 関数 (1/4)[pp.110-111] 機能:ソケットを作成する #include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol); 戻り値 成功時…ソケット記述子,エラー…−1 未使用 LAN/MAN/WAN socket 関数 (2/4)[pp.110-111] ドメイン int type; コネクション型かコネクションレス型を指定 int protocol; TCPあるいはUDPを指定 SOCK_STREAM…コネクション型 SOCK_DGRAM…コネクションレス型 プロトコル ソフトウェア設計及び実験:ネットワークプ ログラミング1 AF_INET…INETドメイン(インターネットドメイン)ネットワーク越し AF_UNIX…UNIXドメイン(同一ホスト内プロセス間通信) タイプ int domain; 通信領域を指定 IP IPPROTO_TCP…TCP/IP IPPROTO_UDP…UDP/IP 0…ドメインとタイプから適切なものを自動選択 6 socket 関数 (3/4)[pp.110-111] アプリケーション層 クライアント サーバ socket 関数 (4/4)[pp.110-111] アプリケーション層 <サーバ, クライアント(UDP/IP)での使用例> int soft; sofd = socket( AF_INET, SOCK_DGRAM, 0); if ( sofd < 0 ){ エラー処理; } プロセス プロセス sofd には 6 が代入される. 準備 準備 ①socket(); 0); ①sofd = socket(AF_INET, SOCK_DGRAM, ②bind(); ②bind(); ネットワーク越し,コネクションレス通信,UDP 送受信(③④繰返し) 送受信(③④繰返し) ③recvfrom(); ③sendto(); UDP/IP上で利用可能な,識別 ④sendto(); ④recvfrom(); 子6番のソケットが生成されている. 終了 終了 ⑤close(); ⑤close(); ソケット ソケット 5 6 この状態では,ポート番号等との 関連付けはなされていない. ポート ポート 13 UDP UDP IP LAN/MAN/WAN IP bind 関数 (1/7)[pp.112-116] bind 関数 (2/7)[pp.112-116] 機能:ソケットに名前を付ける(情報割付) /* INETドメインで利用するアドレス構造体 */ #include <sys/types.h> struct sockaddr_in{ #include <sys/socket.h> short int bind(int s, struct sockaddr* name, int namelen); u_short sin_port; 戻り値 成功時…0,エラー…−1 int s; ソケット記述子 struct sockaddr* name; 対応アドレス構造体へのポインタ int namelen; アドレス構造体のサイズ sin_family; /* ドメイン(常にAF_INET) */ /* ポート番号 */ struct in_addr sin_addr;/* IPアドレス格納構造体 */ char sin_zero[8]; /* パディング */ }; struct u_long in_addr{ s_addr; /* IPアドレス */ } bind 関数 (3/7)[pp.112-116] bind 関数 (4/7)[pp.112-116] アプリケーション層 クライアント サーバ プロセス /* クライアントにおけるアドレス構造体設定例 */ struct sockaddr_in cl_addr; bzero((char*)&cl_addr, sizeof(cl_addr)); /*初期化*/ cl_addr.sin_family = AF_INET; /*ドメイン*/ cl_addr.sin_port = htons( 0 ); /* システム自動割当 */ cl_addr.sin_addr.s_addr = htonl(INADDR_ANY); /* INADDR_ANY = 0 インタフェースの制限なし */ 準備 準備 ①sofd = socket(AF_INET,SOCK_DGRAM,0); ①socket(); ②bind(sofd,(struct sockaddr*)&cl_addr,sizeof(cl_addr)); ②bind(); 送受信(③④繰返し) 送受信(③④繰返し) アドレス構造体 cl_addr ③sendto(); ③recvfrom(); の在処(アドレス)を渡す ④sendto(); ④recvfrom(); 終了 終了 ⑤close(); ⑤close(); struct sockaddr_in cl_addr; ソケット ソケット アドレスファミリー = AF_INET (ドメイン) 自動割当 6 5 ポート番号 = 0 (ワイルドカード⇒システム自動割当) ポート ポート 1032 IPアドレス = INADDR_ANY(0)(インタフェース制限なし) 13 UDP UDP IP ソフトウェア設計及び実験:ネットワークプ ログラミング1 アプリケーション層 プロセス 未使用 LAN/MAN/WAN IP 7 bind 関数 (5/7)[pp.112-116] bind 関数 (6/7)[pp.112-116] サーバ アプリケーション層 プロセス /* サーバにおけるアドレス構造体設定例 */ struct sockaddr_in sv_addr; bzero((char*)&sv_addr, sizeof(sv_addr)); /*初期化*/ sv_addr.sin_family = AF_INET; /*ドメイン*/ sv_addr.sin_port = htons( 13 ); /* 明示的割当 */ sv_addr.sin_addr.s_addr = htonl(INADDR_ANY); /* INADDR_ANY = 0 インタフェースの制限なし */ 準備 ①sofd = socket(AF_INET,SOCK_DGRAM,0); ②bind(sofd,(struct sockaddr*)&sv_addr,sizeof(sv_addr)); 送受信(③④繰返し) アドレス構造体 sv_addr ③ recvfrom(); の在処(アドレス)を渡す ④ sendto(); 終了 ⑤close(); ソケット 明示的割当 5 ポート 13 UDP struct sockaddr_in sv_addr; アドレスファミリー = AF_INET (ドメイン) ポート番号 = 13 (明示的割当) IPアドレス=INADDR_ANY(=0:インタフェース制限なし) 未使用 IP MAN/WAN bind 関数 (7/7)[pp.112-116] メッセージの送受信 <クライアント(UDP/IP)での使用例> structsockaddr_in cl_addr; cl_addr の設定; bind(sofd,(struct sockaddr*)&cl_addr,sizeof(cl_addr)); /*本来なら戻り値の正負を判断し,エラー処理を行う*/ <サーバ(UDP/IP)での使用例> structsockaddr_in sv_addr; sv_addr の設定; bind(sofd,(struct sockaddr*)&sv_addr,sizeof(sv_addr)); /*本来なら戻り値の正負を判断し,エラー処理を行う*/ int s; ソケット記述子 char *buf; 送信メッセージのバッファアドレス int lens; 送信メッセージのサイズ int flag; 送信メッセージのフラグ(通常0,p.146参照) struct sockaddr* to;相手先のアドレス構造体へのポインタ int tolen; アドレス構造体のサイズ ソフトウェア設計及び実験:ネットワークプ ログラミング1 send………コネクション型のみで利用可能 sendto……双方で利用可能 sendmsg…双方で利用可能 受信 sendto 関数 (1/3)[pp.116-119] 機能:メッセージをソケットに送信する #include <sys/types.h> #include <sys/socket.h> int sendto(int s, char *buf, int lens, int flag, struct sockaddr *to, int tolen); 戻り値 成功時…送信されたバイト数,エラー…−1 送信 recv………コネクション型のみで利用可能 recvfrom…双方で利用可能 recvmsg …双方で利用可能 sendto 関数 (2/3)[pp.116-119] アプリケーション層 クライアント 準備 プロセス サーバ アプリケーション層 ①sofd = socket(AF_INET,SOCK_DGRAM,0); ②bind(sofd,(struct sockaddr*)&cl_addr,sizeof(cl_addr)); 送受信(③④繰返し) smsg(送信メッセージ) ③sendto(sofd, smsg, nbyte, 0, (struct sockaddr*)&sv_addr, svadlen); ④recvfrom(); 終了 ⑤close(); ソケット 6 ポート 1032 UDP IP 在処(アドレス)を渡す gethostbyname()で調べる サーバ情報のアドレス構造体 struct sockaddr_in sv_addr; 192.168.1.2 アドレスファミリー = AF_INET ポート番号 =13 IPアドレス =192.168.5.2 未使用 LAN/MAN/WAN ソケット 5 ポート 13 192.168.5.2 UDP IP 8 gethostbyname関数(3/3)[pp.120-121,124] shost = gethostbyname(”tama.is.tokushima-u.ac.jp”); struct hostent *shost; shost = ・ h_name=・ h_aliases=・ h_addrtype = AF_INET h_length = 4 h_addr_list=・ h_addr (=h_addr_list[0]) アドレスリスト 150 59 38 197 : 1バイトづつコピー struct sockaddr_in sv_addr; sin_family = AF_INET sin_port = 13 #define PORT_NO 13 sin_addr bzero((char*)sv_addr,sizeof(sv_addr)); s_addr=150.59.38.197 sv_addr.sin_family = AF_INET; 未使用 sv_addr.sin_port = htons(PORT_NO); bcopy(short->h_addr, (char*)&sv_addr.sin_addr.s_addr, p.113表4.2参照 short->h_length ); recvfrom 関数 (1/2)[pp.116-119] 機能:メッセージをソケットから受信する #include <sys/types.h> #include <sys/socket.h> int rcvfrom(int s, char *buf, int lens, int flag, struct sockaddr *from, int *fromlen); 戻り値 成功時…受信したバイト数,エラー…−1 int s; ソケット記述子 char *buf; 受信メッセージのバッファアドレス int lens; 受信メッセージのサイズ int flag; 受信メッセージのフラグ(通常0,p.147参照) struct sockaddr* from;送信元のアドレス構造体へのポインタ int *fromlen; アドレス構造体のサイズへのポインタ recvfrom 関数 (2/2)[pp.116-119] アプリケーション層 クライアント 準備 プロセス サーバ アプリケーション層 ①sofd = socket(AF_INET,SOCK_DGRAM,0); ②bind(sofd,(struct sockaddr*)&cl_addr,sizeof(cl_addr)); 送受信(③④繰返し) rmsg(受信メッセージが書き込まれる) ③sendto(sofd, smsg, nbyte, 0, (struct sockaddr*)&sv_addr, svadlen); ④recvfrom(sofd, rmsg, BUFFMAX, 0, (struct sockaddr*)&sv_addr,&cladlen); ソケット ソケット 終了 サーバ情報のアドレス構造体 6 struct sockaddr_in sv_addr; 5 ⑤close(); ポート アドレスファミリー = AF_INET ポート 送信元情報(誰 1032 13 UDP UDP ポート番号 =13 が送ってきたの IPアドレス =192.168.5.2 か)がアドレス構造 IP 192.168.1.2 192.168.5.2 IP 体に記入される LAN/MAN/WAN 未使用 close 関数 (1/2)[pp.95-96] 機能:ソケットを閉じる #include <unistd.h> int close(int d); 戻り値 成功時…0,エラー…-1 int s; ファイル(ソケット)記述子 close 関数 (2/2)[pp.95-96] アプリケーション層 クライアント サーバ アプリケーション層 準備 プロセス プロセス ①sofd = socket(AF_INET,SOCK_DGRAM,0); 準備 ②bind(sofd,(struct sockaddr*)&cl_addr,sizeof(cl_addr)); ①socket(); 送受信(③④繰返し) ②bind(); ③sendto(sofd, smsg, nbyte, 0, 送受信(③④繰返し) (struct sockaddr*)&sv_addr, svadlen); ③recvfrom(); ④recvfrom(sofd, rmsg, BUFFMAX, 0, ④sendto(); (struct sockaddr*)&sv_addr,&svadlen); 終了 終了 ⑤close(sofd); ⑤close(); ソケット ソケットを閉じる ソケット 6 5 ポート ポート 1032 13 UDP UDP IP 192.168.1.2 LAN/MAN/WAN その他 IP ソフトウェア設計及び実験:ネットワークプ ログラミング1 9 select 関数 (1/7) [pp.168-170] select 関数 (2/7) [pp.168-170] 送受信関数・入出力関数は通常ブロックされる 複数の送受信・入出力がスムーズに行えない select 関数の使用 サーバ アプリケーション層 クライアント アプリケーション層 int fn; fn = fileno(stdin); /*fn には 0 が代入される*/ read(fn, msg, MAXMSG); キーボード入力が終わるまでソケット recvfrom(sofd, 略…); ソケット 6 ポート UDP 1032 IP sofdからのメッセージ受信ができない ファイル (整数)記述子 0 ソケット 5 ポート 13 UDP LAN/MAN/WAN IP select 関数 (3/7) [pp.168-170] int nfsd; ビットマスク中の使用ビット幅 fd_set* rfsd; 読取可能なファイル記述子を監視する ためのビットマスクへのポインタ fd_set* wfsd; 書取可能なファイル記述子を監視する ためのビットマスクへのポインタ fd_set* efsd; 例外状態のファイル記述子を監視する ためのビットマスクへのポインタ select 関数 (5/7) [pp.168-170] ビットマスクのビット操作マクロ int fd; fd_set fdset; FD_ZERO(&fdset);ビットマスクを0クリア FD_SET(fd, &fdset);ファイル(整数)記述子fdを ビットマスク fdset にセットする FD_CLR(fd, &fdset);ファイル(整数)記述子 fd を ビットマスク fdset から除く FD_ISSET(fd, &fdset); ファイル(整数)記述子 fd が ビットマスク fdset に含まれるなら 1を,含まれないなら0を返す ソフトウェア設計及び実験:ネットワークプ ログラミング1 機能 入出力の多重待ち #include <sys/types.h> #include <sys/time.h> #include <unistd.h> int select(int nfsd, fd_set* rfsd, fdset* wfsd, fdset* efsd, struct* timeout); 戻り値 成功時…ビットマスク中に含まれるI/O可能な ファイル記述子 タイムアウト…0 エラー…−1 select 関数 (4/7) [pp.168-170] struct timeval* timeout; timeval構造体へのポインタ NULLのとき: selectはブロック NULL以外のとき: select が完了するまでの最大待ち 時間を書いたtimeval構造体のアド レスを指定 select 関数 (6/7) [pp.168-170] ファイル記述子・ファイル整数記述子変換関数 #include <stdio.h> int fileno(FILE *stream); 戻り値 ファイル整数記述子 FILE *stream; ファイル記述子 例) fileno(stdin) → 0 fget(msg,MAXMSG,stdin); 等価 fileno(stdout) → 1 read(0,msg,MAXMSG); fileno(stderr) → 2 10 select 関数 (7/7) [pp.168-170] アプリケーション層 ビットマスクrfsd_org int fin, max_rfd; fd_set rfsd, rfsd_org; 63 … 7 6 5 4 3 2 1 0 0 … 0 1 0 0 0 0 0 1 fin = fileno(stdin); FD_ZERO(&rfsd_org); 使用ビット幅 = 7 FD_SET(fin, &rfsd_org); FD_SET(sofd, &rfsd_org); select後 max_rfd = (fin<sofd) ? sofd: fin; 読出し可能 課題 63 … 7 6 5 4 3 2 1 0 rfsd while(1){ rfsd = rfsd_org; 0 … 0 1 0 0 0 0 0 0 select( max_rfd + 1, &rfsd, NULL, NULL, NULL); if(FD_ISSET(fin, &rfsd)) read(fin, msg, MAXMSG); if(FD_ISSET(sofd, &rfsd)) recvfrom(sofd, 略…); } UDP ファイル (整数)記述子 0 ソケット 6 ジャンケンゲームの概要 目的 TCP/IP プロトコルの仕組みの理解 UDPプログラミングの理解 サーバ・クライアント型プログラム トランスポートプロトコルはUDP 同時ゲーム参加クライアント数:2台まで 3台以上のゲーム参加は拒絶 ジャンケンゲームサーバの作成 メッセージシーケンス概要(1/2) クライアント1 サーバ connect message message送受信 close message connect message メッセージシーケンス概要(2/2) クライアント2 message送受信 close message close message any message 他のクライアント 途中参加のクライアント はいかなるメッセージを 送っても close メッセージ が返るのみで無視 ソフトウェア設計及び実験:ネットワークプ ログラミング1 クライアント1 connect message message送受信 reset message close message サーバ connect message message送受信 クライアント2 close message 両方(クライアント2にも)のクライアントに close メッセージを送信し,強制リセット 11 クライアントの実行例 サーバの実行例 使用方法: client [server_name] [server_port] 強制終了:reset+改行をコマンドライン入力 サーバの内部状態遷移 使用方法: server [server_port] 終了方法: quit+改行をコマンドライン入力 サーバの内部状態遷移図 ①クライアントからconnect コマンドを以外を受信 4状態間を遷移 NON_PERSON: ゲームに誰も参加していない ONE_PERSON: 1人ゲームに参加 TWO_PERSONS: 2人ゲームに参加 FIRST_TOSS: 1人が既にグー,チョキ,パーの どれかを出している 調査課題 UDPとTCPの違いをA4用紙1枚程度で述べよ. プログラム課題 ジャンケンゲームサーバを完成させよ. サーバの状態遷移図を完成させ,この図を使って サーバプログラムの動作を詳細に解説せよ. サーバプログラムの各行にコメントを加え,レポート の付録として添付せよ. ソフトウェア設計及び実験:ネットワークプ ログラミング1 NO_PERSON 開始 ②クライアントからconnect メッセージを受信 クライアント1として保存 ③コマンドラインから quit コマンドを入力 ④クライアント1からconnect ONE_PERSON コマンドを受信 ⑤クライアント1以外からconnect 終了 コマンド以外を受信 ①:connect message を送信 ⑦コマンドラインから ⑥クライアント1 するよう通知 quit コマンドを入力 以外から ②… connectコマン 終了 ③… ドを受信 レポート課題(1/2) ⑦クライアント1から reset コマンドを受信 レポート課題(2/2) プログラム課題(つづき) プログラムをメールに添付し,太田まで提出せよ. 添付にあたっては次の指示を守ること. Makefile も含めすべてのソースファイル(*.c, *.h)を tar で圧縮しつつ,ひとつにまとめる. 例) tar cvfz program.tgz *.c *.h Makefile メールアドレス:[email protected] サブジェクト: network programming 1 12 利用可能なリソース サンプル・ソース・バイナリの在処 http://baltan.is.tokushima-u.ac.jp /~ohta/lecture/experiment/ /network-programming/index.html プログラム一式 Makefile toss_game.h toss_game.c client.c server.c 手を加えてよい 手を加えてよい 手を加えてよい 手を加えてよい 未完成 ⇒ 完成させよ(課題) ソフトウェア設計及び実験:ネットワークプ ログラミング1 13
© Copyright 2024 Paperzz