第5回授業

第5回ネットワークプ
ログラミング
中村 修
今日のお題

講義
7
layer modelのおさらい
 TCPとUDP
 ネットワークプログラミング基本手順

練習1:echo clientを作ろう
---------休憩------------------------------- 実習:UDPでデータを送る/受け取る
 udpで
echo serverを作ろう
インターネットの階層モデル
アプリケーション
アプリケーション
TCP
IP
データリンク
物理
IP
データリンク
物理
TCP
IP
データリンク
物理
OSI参照モデルと
インターネットの階層構造の関係
アプリケーション
プレゼンテーション
アプリケーション
セッション
トランスポート
TCP
UDP
ネットワーク
IP
データリンク
Network Interface
物理
物理
階層型プロトコルでのデータ送受信

送信側
 各層がそれぞれ必要な情報を付加して下層へ渡す

受信側
 各層がそれぞれ情報をもとに処理を行い、その使った
各層の
情報
情報を取り除いて上層へ渡す
データ
アプリケーション
アプリケーション
TCP
TCP
UDP
UDP
IP
IP
Network Interface
Network Interface
物理
物理
送信ノード
受信ノード
データ
プロトコル

2つの機器間で,通信の手順を決めた約束ご
と
 IP,TCP,HTTP,FTP

コンピュータは「決まり」がないと通信できない
ネットワークアプリケーションとは?
process
process
TCP
UDP
IP
ICMP
process
process
ARP
transport
layer
IGMP
network
layer
RARP
hardware
interface
media
data link
layer
クライアント・サーバモデル

ネットワークを介したサービスにおける通信モデル

サーバ


受動的にサービス提供する側、待っててくれる
クライアント

能動的にサービス提供を促す側、接続しに行く
Client
Server
サービス要求
サービス提供
ポートとソケット

ポート
 トランスポート層のアクセスポイント
 TCP/UDP毎に持っている

ソケット
 プロセスとポートを繋ぐアダプタ
ソケット(Socket)



プロセス間通信を行う為のデータの出入り口
プロセスからはファイルディスクプリタを用いてアクセス
プロセスにとってはプロセス間通信もファイル入出力も同じ
インターフェイス
プロセス
socket
socket
プロセス
socket()システムコール

int socket(int family, int type, int proto)
 familyにはプロトコルファミリを指定




AF_INET
AF_INET6
AF_LOCAL
AF_ROUTE
IPv4プロトコル
IPv6プロトコル
UNIX Domain Socket
経路制御ソケット
 Typeにはソケットのタイプ(以下のどれか)



SOCK_STREAM
SOCK_DGRAM
SOCK_RAW
ストリームソケット
データグラムソケット
rawソケット
 Protoにはrawソケット以外、通常0
socket()システムコール

返り値


成功: ソケットディスクリプタが返る
失敗: -1が返る

ソケットディスクリプタはファイルディスクリプタの友達

実際のコードでは…
listenfd = socket(AF_INET, SOCK_STREAM, 0)

AF_INETの場合の利用されるIPv4の上位層



SOCK_STREAM
SOCK_DGRAM
SOCK_RAW
TCP
UDP
なし
初期状態
クライアント
プロセス
Port A
サーバ
プロセス
Port B
Port C
ホストA
IP Address: xx.xx.xx.xx.
ホストB
IP Address: xx.xx.xx.xx.
Socketを開いた状態
Socketを開く
クライアント
プロセス
Port A
サーバ
プロセス
Port B
Port C
ホストA
IP Address: xx.xx.xx.xx.
ホストB
IP Address: xx.xx.xx.xx.
bindした状態
Proto LocalAdddress
TCP
*.A
クライアント
プロセス
ForeignAddress
*.*
Port A
State
Closed
サーバ
プロセス
Port B
Port C
ホストA
IP Address: xx.xx.xx.xx.
ホストB
IP Address: xx.xx.xx.xx.
Stream
example
(TCP)
Server
socket()
bind()
Client
listen()
socket()
accept()
Connection Establishmt.
Block until
connect
recv()
Process
request
send()
Data (request)
connect()
send()
Data (reply)
recv()
暗黙にbind()
Datagram
example
(UDP)
Server
socket()
Client
bind()
socket()
recvfrom()
bind()
Block until
Data from
client
Data (request)
sendto()
Process
request
sendto()
Data (reply)
recvfrom()
Datagram
example2
(UDP)
Server
socket()
Client
bind()
socket()
recvfrom()
bind()
Block until
Data from
client
connect()
Data (request)
send ()
Process
request
sendto()
Data (reply)
recv ()
sockaddr_in構造体

ソケットの情報
… 32bit
 ポート番号 … 16bit
 プロトコルファミリー … AF_INET…
7
15
0
 アドレス
長さ
protocol
アドレス
unused
unused
Port番号
31
sockaddr構造体

ソケットの情報を一般化した形
 ソケットを使った通信のためのテンプレート
 利用するプロトコルに依存しない
 共通:
長さ・プロトコルファミリ(AF_XXX)
7
15
0
unused
長さ protocol
unused
unused
unused
31
キャスト

ある変数・構造体を無理やり違う型の変数や構造体として扱
う方法

変数を使う時に扱いたい型をカッコで括る


関数の引数を一般化するのに便利



(int)no_int_variable; ← int型にキャスト
sockaddrの例
struct sockaddr_in sin; (struct sockaddr)sin;
型やサイズに依存せず1バイトずつ読みたいときにも使う
long addr = 1234567; char *cp = (char *)&addr;
for(j = 0; j < 4; j++) {
printf("%c ", *cp++);
}
inet_addr()
in_addr_t inet_addr(const char
*strptr);
 アドレスを表す文字列を,
ネットワークバイト順序のバイナリ値へ
 「127.0.0.1 」という文字列は人間には分か
りやすいが,コンピュータには分かりにくい
 仲間

 inet_aton()
 inet_ntoa()
ネットワーク・バイト・オーダ


Network Byte Order
CPUアーキテクチャによって、バイトの並びが違う


ネットワーク上に流すバイト順を統一しなくてはならない


一般にBig Endian(sparc等)とLittle Endian(Intel等)の二つ
Big Endianに統一
htons()/htonl()/ntohs()/ntohl()を利用
リトルエンディアン
16ビット整数
(short)
32ビット整数
(long)
1 2
1 2 3 4
ビッグエンディアン
2 1
4 3 2 1
エンディアン変換
u_long htonl(u_long hostlong);
 u_short htons(u_short hostshort);
 u_long ntohl(u_long netlong);
 u_short ntohs(u_short netshort);

練習1:echoクライアント作成

echoサーバは以下
hi.sfc.wide.ad.jp
port 7番
必要な構造体
#include<netinet/in.h>
struct sockaddr_in{
u_char sin_len;
u_char sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
}

/*IP addressのサイズ*/
/*AF_INET etc*/
/*port num*/
/*IP address*/
/*padding*/
必要な関数
socket
 bind
 sendto
 recvfrom

socket
 int
socket(int domain, int type, int protocol);
(例)
sd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP)
AF_UNIX , SOCK_STREAM,IPPROTO_TCP
SOCK_RAW,IPPROTO_ICMP
bind
int bind(int sockfd,struct sockaddr *addr,int addrlen);
(例)

struct sockaddr_in server;
memset((void *)&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(7);
server.sin_addr.s_addr = INADDR_ANY; /* local host*/
bind(sd,(struct sockaddr *)&server, sizeof(server))
sendto

ssize_t sendto(int s, const void *msg, size_t
len, int flags, const struct sockaddr *to, int
tolen);
(例)
if (sendto(s, (char *)&msg, sizeof(msg), 0 , (struct
sockaddr *)&server, sizeof(server)) < 0) {
perror("sendto");
exit(-1);
}
recvfrom
ssize_t recvfrom(int s, void *buf, size_t
len, int flags, struct sockaddr *from, int
*fromlen);
(例)

recvlen = recvfrom(sd, (void *)buf, 1024, 0,
(struct sockaddr *)&client, &clientlen);
実習
echoサーバを作ろう。
 基本的にechoクライアントと同じ
 sendto,recvfromの順番が逆