PPT資料 - 静岡大学情報学部 峰野研究室

Download Report

Transcript PPT資料 - 静岡大学情報学部 峰野研究室

ネットワークプログラミング
の基礎
CS-B3 ネットワークプログラミング
峰野博史 (mineno@inf.)
1
これまでの学習項目

Cプログラミング基礎


実用的な使い方





配列,関数,再帰関数,構造体,ポインタ,etc.
キーボード入力,画面出力
ファイル入出力
リダイレクト,コマンドライン引数
統合開発環境,etc.
他にも様々なことができます
2
その他の重要項目(一部)

実践アルゴリズム






ネットワークプログラミング


計算量,スタック,キュー,連結リスト,木構造
ハッシュ法,二分探索木,AVL木,B木
整列,クイックソート
ワイルドカードマッチング
正規表現,バックトラック,グラフ探索,etc.
TCP/UDP,ソケットAPI,プロセス間通信,etc.
その他

メモリ管理,プロセス,スレッド,システムコール,etc.
3
ネットワークプログラミング基本

ケーブルをPCに挿入する,もしくは無線LANのキ
ーを設定するだけで世界中のホームページが見
られたり,電子メールを送受信できる



なぜでしょう?
つながらない時は何を調べればよいのでしょう?
大切な考え方: 機能の階層的な管理!
4
機能の階層的な管理

ソフトウェア






アプリケーション
ライブラリ
OS
デバイスドライバ
BIOS
アプリケーションソフトウェア
ライブラリ関数


ディスプレイ
キーボード
マウス
(サービスの要求)
(サービスの要求)
オペレーティグシステム(OS)
(ハードウェアの制御)
ハードウェア

システムコール
デバイスドライバ
(OSの設定)
(ハードウェアの制御)
ファームウェア
(ハードウェアの設定
/制御)
ハードウェア
5
ライブラリ関数とシステムコール

ライブラリ関数




ライブラリに収められた関数群
内部でシステムコールを使って実装されることもある
time(), rand(), strlen(), printf(), sscanf(), etc.
システムコール


(サービスコール,スーパーバイザコールとも言う)
OS(特にカーネル)の機能を呼び出すための機構
open, read, write, fork, socket, stat, unlink, etc.
6
ネットワークモジュールの利用
アプリケーション
システムコール
アプリケーションソフトウェア
プロセスの切り替え
ユ
ー
ザ
モ
ー
ド
アプリケーションインターフェイス
トランスポートモジュール(TCP・UDP)
インターネットモジュール(IP)
関数呼び出し
ソフトウェア割り込み
デバイスドライバ
ドライバモジュール
メモリまたはI/O
ポートへの書き込み
オペレーティングシステム
(OS)
カ
ー
ネ
ル
モ
ー
ド
ハードウェア割り込み
ネットワークインターフェイスカード
ハードウェア
7
通信機能の「レイヤ」の考え方

Webページ www.yahoo.co.jp が見れない?






Webサーバがダウン?
www.yahoo.co.jp というホスト名が見つからない?
自端末にIPアドレスが設定されていない?
経路上のルータがダウン?
自端末のNIC(Network Interface Card)の故障?
レイヤ毎に決められた機能間の関連(プロトコル
)を理解すれば,問題の所在を突き止められる

どのレイヤまで動けば何が動くはずか
8
無理やり現実社会に例えると..
住所を書いて手紙をポスト
へ投函すると相手に届く




住所を割り当てる
住所から配送経路を求める
郵便局を配置する
最寄りの郵便局まで歩く

IPアドレスを指定してパケッ
トを送信すると相手に届く




IPアドレスを割り当てる
ルーティングプロトコルで配送
ルータを設置する
LANや無線LANなどで通信
現実社会
通信
名前
ホスト名
部屋番号
ポート番号
住所
IPアドレス
配送経路を決める
ルーティングプロトコル
郵便局
ルータ
郵便局まで歩く
LAN,無線LANなど
レイヤ構造

9
通信におけるレイヤ毎の識別子
アプリケーションレベル: ホスト名,ドメイン名


人間が理解しやすい名前:
www.yahoo.co.jp など
トランスポートモジュールレベル: ポート番号


同一通信機器内で通信を区別する識別子:
http: 80, SMTP: 25 など
インターネットモジュールレベル: IPアドレス


通信機器を区別する識別子:
124.83.235.204 など
デバイスドライバレベル: MACアドレス


通信機器を区別する世界で一つの識別子:
08:00:27:dd:2d:94 など
アプリケーション
アプリケーション
トランスポート
モジュール
インターネット
モジュール
デバイスドライバ
インターネット
モジュール
デバイスドライバ
インターネット
モジュール
デバイスドライバ
トランスポート
モジュール
インターネット
モジュール
デバイスドライバ
ハードウェア
ハードウェア
ハードウェア
ハードウェア
ホストA
ケーブル
ルータX
ケーブル
ルータY
ケーブル
ホストB
ホスト名
ドメイン名
ポート番号
IPアドレス
MACアドレス
10
通信開始時の識別子変換処理①
1.
2.
3.
4.
アプリケーション層: ホスト名,ドメイン名
トランスポート層: ポート番号
インターネット層: IPアドレス
2.サービス名からポート番号を調べる
ホストA
services
データリンク層: MACアドレス
services ファイルから検索
1.ホスト名,ドメイン名からIPアドレスを調べる
hosts
ホストA
①
DNSデータベース
DNS
サーバA
②
①hostsファイルから検索
②DNSサーバに問い合わせる
③ハードディスクのデータベースから検索
③
DNSキャッシュ
DNSサーバ類
④
⑤
④DNSのキャッシュから検索
⑤他のDNSサーバへ問い合わせる
11
通信開始時の識別子変換処理②
3. IPアドレスから,次に送るべきホストやルータを決定
ネットワークB
ネットワークA
> route PRINT
ホストA
ルーティングテーブル
ホストB
ルータA
ルータB
終点IPアドレスからルーティングテーブルを検索し,次にパケットを転送すべきホストやルータを決定する
4. IPアドレスから,MACアドレスを調べる
> arp -a
ホストA
①
④
ARPテーブル
ホストB
ホストC
ホストD
ホストE
②
③
①ARPテーブルを検索
※ARP (Address Resolution Protocol)
②ARPテーブルにない場合にはARP要求パケットを送信
③自分のIPアドレスに対するARP要求パケットの場合には,ARP応答パケットでMACアドレスを通知する
12
④通知された情報をARPテーブルに追加する(キャッシュ)
IPアドレス,MACアドレスの調べ方

$ ifconfig -a
IPv4アドレス
MACアドレス
13
通信におけるレイヤ毎の役割

アプリケーション層: FTP,telnet,HTTP,DNS,POP3,など


トランスポート層: TCP,UDP,など


宛先・送信元アプリケーションの特定,誤り制御,シーケンス制御
インターネット層: IPv4,IPv6,ARP,ICMP,など


様々な用途に依存した処理
起点から終点までのパケット配送(ルーティング)を提供する
データリンク層: Ethernet,IEEE 802.11,PPP,など

隣接する通信機器間でのフレーム配送を提供する
アプリケーション
アプリケーション
トランスポート
モジュール
インターネット
モジュール
デバイスドライバ
インターネット
モジュール
デバイスドライバ
インターネット
モジュール
デバイスドライバ
トランスポート
モジュール
インターネット
モジュール
デバイスドライバ
ハードウェア
ハードウェア
ハードウェア
ハードウェア
ホストA
ケーブル
ルータX
ケーブル
ルータY
ケーブル
ホストB
ホスト名
ドメイン名
ポート番号
IPアドレス
MACアドレス
14
通信プロトコルとは?


ネットワークを介してコンピュータ同士が通信を行なう上
で,相互に決められた約束事の集合
通信手順,通信規約
 プログラム = データ構造 + アルゴリズム

プロトコル = パケットの構造 + 動作の定義
–
1年生:計算機システム演習,プログラミング(科学科)

–
2年生:コンピュータネットワーク講義

–
通信の仕組みの基礎を理解
代表的なTCP/IPプロトコル動作の詳細を理解
3年生:ネットワーク系研究室

通信プロトコル改良研究,ネットワークシステム開発研究
15
トランスポート層プロトコル

TCP(Transmission Control Protocol)

IPの機能を拡張し,終点ホスト間で信頼性のある通信を提供


コネクション指向のプロトコルで,通信開始時にコネクションを
確立し,通信終了時にコネクションを切断


送信データの順序番号制御と確認応答制御を実行
HTTPやSMTPなど多くのアプリケーションで利用
UDP(User Datagram Protocol)


IPの機能をそのままアプリケーションから利用
コネクションレスで信頼性のないデータグラム型のサービスを
提供

マルチメディアストリームを扱うアプリケーションでよく利用
16
ネットワークプログラミング

ソケットシステムコール

アプリケーションがOS
内の通信関係のモジュ
ールを利用するための
インタフェース
アプリケーション
メッセージの送信
メッセージの受信
アプリケーション
sendシステムコール
システムコール
オペレーティングシステム
ソケットモジュール
ソケット
送信キュー
recvシステムコール
プロセスの
切替え
ソケット
受信キュー
関数呼出し
TCPモジュール
関数呼出し
TCP送信
キュー
TCP受信
キュー
関数呼出し

ソケットの種類


コネクション型:TCP
コネクションレス型:UDP
IPモジュール
関数呼出し
IP送信
キュー
IP受信
キュー
ソフトウェア
割込み
関数呼出し
デバイスドライバ
IP送信
キュー
IP受信
キュー
ハードウェア
割込み
I/Oコントロール
ハードウェア
NIC
NIC送信
キュー
パケットの送信
NIC受信
キュー
パケットの受信
17
クライアントサーバモデル


クライアント: 処理を要求するプログラム
サーバ: 要求を受けて処理するプログラム
(A)クライアントとサーバが別々のコンピュータで動作
ホストA
クライアント
プログラム
ホストB
要求
サーバ
プログラム
応答
(B)クライアントとサーバが同じコンピュータで動作
ホストC
クライアント
プログラム
要求
サーバ
プログラム
応答
(C)1つのプログラムがクライアントとサーバを兼ねる
ホストD
クライアント
プログラム
要求
応答
ホストE
1つのプログラム
サーバ クライ
アント
要求
応答
MTA (Mail Transfer Agent),
Web Proxy Server など
ホストF
サーバ
プログラム
18
TCP通信の流れ
以下重要
クライアント側プログラム
サーバ側プログラム
socket()
ソケット作成
socket()
ソケット作成
接続相手の
IPアドレスとポート番
号の設定
接続待ちをする
IPアドレスとポート番
号の設定
bind()
ソケットに名前を付ける
listen()
接続を待つ
connect()
接続要求する
accept()
接続を受け付ける
send()
recv()
通信を行う
通信を行う
recv()
close()
終了する
send()
close()
終了する
19
UDP通信の流れ
クライアント側プログラム
サーバ側プログラム
socket()
ソケット作成
socket()
ソケット作成
接続相手の
IPアドレスとポート番
号の設定
接続待ちをする
IPアドレスとポート番
号の設定
bind()
ソケットに名前を付ける
sendto()
recvfrom()
通信を行う
通信を行う
recvfrom()
close()
終了する
sendto()
close()
終了する
20
socket()

クライアント側
サーバ側
ソケット作成
int sid = socket(PF_INET, SOCK_STREAM, 0);

ファイルアクセスの open() に相当


PF_INET


返り値は,ファイルディスクリプタ
IPv4という通信体系を用いることを指定
SOCK_STREAM

TCPを用いた通信を指定
21
ファイルディスクリプタとは

クライアント側
サーバ側
ファイルや標準入出力に振られる識別子

OSがそれぞれを識別するために使用する





0は標準入力(stdin)
1が標準出力(stdout)
2が標準エラー出力(stderr)
3以降はopenされたファイルに順次割り当てる
Unix/Linuxではソケットもファイルとして扱う
22
bind()

サーバ側
作成したソケットにポート番号などの名前を割り当てる
bind()へ渡すために,まずはどのIPアドレスとポート番号で
待ちうけたいかを専用の構造体へ設定する
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(50001);
int ret = bind(sid, (struct sockaddr *)&addr, sizeof(addr));
 AF_INET: IPv4のアドレスであることを示す
 INADDR_ANY: 自身の全IPへの接続を許可することを示す
 htons(): ネットワークバイトオーダへ変換




送受信するバイトの順番で,TCP/IPは最上位バイトから順番に記録/
送信するビッグエンディアンとなる
クライアント側UDP送信元ポート番号などの指定が
23
不要な場合は bind() しなくてもよい
bind()でよく発生するエラー

サーバ側
「Address already in use」




要求したポート番号が既に使われていますよ
基本的には,ソケットをきちんと close() すればOK
close() すればそのポート番号は再利用可能
ただし,close() してから実際に再利用可能になるま
で少し時間がかかる

そのポートに対してどこかからパケットが飛んでくる可能性
があるから
※bind()に限らず全てのシステムコールで,成功したかどうか
エラー処理を記述しておくべき
24
listen()

サーバ側
TCPコネクション要求を受け付け開始しますよと
いう宣言
int ret = listen(sid, 10);

クライアントからのTCPコネクション接続要求(
connect()システムコール)を受け付ける


接続相手とTCPコネクションを張るのは後述の accept()
第二引数の数字は,複数の接続要求が同時に殺到
し accept() が間に合わない時,いくつまでTCPコネ
クションを保持できるかの最大数
25
connect()

クライアント側
指定したIPアドレスとポート番号へ接続要求

connect()へ渡すために,まずはIPアドレスとポート番号を専用の
構造体へ設定する
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(“192.168.1.100”);
addr.sin_port = htons(50001);
int ret = connect(sid, (struct sockaddr *)&addr, sizeof(addr));



AF_INET: IPv4のアドレスであることを示す
inet_addr(): IPアドレス文字列を32bit形式に変換
htons(): ネットワークバイトオーダへ変換

送受信するバイトの順番で,TCP/IPは最上位バイトから順番に記録/送信
するビッグエンディアンとなる
26
accept()

サーバ側
待ちうけポートでTCPコネクション接続要求を受け,クラ
イアントと通信するための新たなソケットを生成

struct sockaddr_in client_addr;
socklen_t len = sizeof(client_addr);
int ss = accept(sid, (struct sockaddr *)&client_addr, &len);


以下のクライアントの情報を client_addr へ受け取る
accept() に成功したら,以降クライアントとの送受信は,この
新たなソケットを用いて実施される
27
クライアント側
サーバ側
send()/sendto()/recv()/recvfrom()

TCPコネクション確立後にデータの送受信が可能
n = send(sid, data, N, 0);
もしくは
n = recv(sid, data, N, 0);


ファイルアクセスの read() や write() に相当
UDPでデータの送受信が可能
n = sendto(sid, data, N, 0, &dest_addr, sizeof(dest_addr));
もしくは
n = recvfrom(sid, data, N, 0, &from_addr, &from_len);

ファイルアクセスの read() や write() に相当
28
close()/shutdown()

クライアント側
サーバ側
ソケットを閉じる
close(sid);


作成したソケットを終了し,これ以降,このソケットを
用いることはできない
自身の送信は終了するが,やってくるデータは
受け取りたい場合
shutdown(sid, SHUT_WR);

現段階ではあまり気にしなくて良い
29
gethostbyname()

ホスト名からIPアドレスへの変換を行ってくれる関数
#include <netdb.h>
struct hostent *addr;
/* アドレス情報を格納するhostent構造体 */
/* IPアドレス取得 */
if ((addr= gethostbyname(argv[1]) == NULL){
printf(“gethostbyname() failed!\n");
}
printf(“gethostbyname() Success!!\n");
/* 失敗すると NULL */
30
※引数型の詳細は処理系に依存しますので man コマンドで確認しましょう
まとめ:主要なソケットシステムコール





socket() ソケットを開く
close() ソケットを閉じる
bind()
自ホストのIPアドレス,ポート番号の設定
listen() TCPコネクションの受け付け開始
connect()
TCPコネクション確立要求








相手ホストのIPアドレス,ポート番号を指定
accept() 受け付けたTCPコネクション用にソケットを作成
send() メッセージの送信(TCP)
sendto() メッセージの送信(UDP)
recv()
メッセージの受信(TCP)
recvfrom()
メッセージの受信(UDP)
select() 入出力の多重化
setsockopt()
ソケットオプションの設定
31
※引数型の詳細は処理系に依存しますので man コマンドで確認しましょう
まとめ:主要なソケットライブラリ関数












gethostbyname()
ドメイン名からIPアドレスを取得
gethostbyaddr()
IPアドレスからドメイン名を取得
getservbyname()
キーワードからポート番号を取得
getservbyport()
ポート番号からキーワードを取得
inet_addr()
文字列のIPアドレスを構造体に変換
inet_ntoa()
IPアドレス構造体を文字列に変換
htonl() ネットワークバイトオーダに変換(long)
htons() ネットワークバイトオーダに変換(short)
ntohl() ホストバイトオーダに変換(long)
ntohs() ホストバイトオーダに変換(short)
getaddrinfo() ドメイン名からIPアドレスを取得,
キーワードからポート番号を取得
getnameinfo() IPアドレスからドメイン名を取得,
32
ポート番号からキーワードを取得
まとめ:主要なソケット構造体

sockaddr_in構造体:

IPアドレスやポート番号などを格納
通常,自分と相手用の情報を格納する2つの変数を用意
struct sockaddr_in {
u_char sin_family;
/* address family(通常はAF_INET) */
u_short
sin_port;
/* ポート番号(htonsでネットワークバイトオーダに) */
struct in_addr sin_addr; /* IPアドレスを格納したin_addr構造体 */
char
sin_zero[8]; /* 通常は0で初期化しておく */
};

in_addr構造体:
IPアドレスを格納
struct in_addr {
u_int32_t
s_addr;
};

hostent構造体:
struct hostent {
char *h_name;
char **h_aliases;
int h_addrtype:
int h_length;
char **h_addr_list;
};
/* IPアドレスをネットワークバイトオーダで*/
通常,gethostbyname()によってホスト情報を格納
/*
/*
/*
/*
/*
ホストの正式名称(FDQN) */
ホストの別名 */
アドレスタイプ(通常はAF_INET) */
アドレスのサイズ(IPv4の場合4,IPv6の場合16) */
アドレスのリスト(通常,define h_addr h_addr_list[0] ) */
33