第5回ネットワークプログラミング 中村 修
今日のお題 講義 ---------休憩-------------------------------- 7 layer modelのおさらい TCPとUDP ネットワークプログラミング基本手順 練習1:echo clientを作ろう ---------休憩-------------------------------- 実習:UDPでデータを送る/受け取る udpで echo serverを作ろう
インターネットの階層モデル TCP TCP IP IP IP データリンク データリンク 物理 物理 物理 アプリケーション
OSI参照モデルと インターネットの階層構造の関係 セッション トランスポート アプリケーション プレゼンテーション ネットワーク データリンク 物理 アプリケーション TCP UDP IP Network Interface 物理
階層型プロトコルでのデータ送受信 送信側 受信側 各層がそれぞれ必要な情報を付加して下層へ渡す 各層がそれぞれ情報をもとに処理を行い、その使った情報を取り除いて上層へ渡す 各層の 情報 アプリケーション アプリケーション データ データ TCP UDP TCP UDP IP IP Network Interface Network Interface 物理 物理 送信ノード 受信ノード
プロトコル 2つの機器間で,通信の手順を決めた約束ごと IP,TCP,HTTP,FTP コンピュータは「決まり」がないと通信できない
ネットワークアプリケーションとは? transport layer IP network layer data link layer process process process process TCP UDP transport layer ICMP IP IGMP network layer ARP RARP data link layer hardware interface media
クライアント・サーバモデル ネットワークを介したサービスにおける通信モデル サーバ クライアント Client Server サービス要求 受動的にサービス提供する側、待っててくれる クライアント 能動的にサービス提供を促す側、接続しに行く Client Server サービス要求 サービス提供
ポートとソケット ポート トランスポート層のアクセスポイント TCP/UDP毎に持っている ソケット プロセスとポートを繋ぐアダプタ
ソケット(Socket) プロセス間通信を行う為のデータの出入り口 プロセスからはファイルディスクプリタを用いてアクセス プロセスにとってはプロセス間通信もファイル入出力も同じインターフェイス プロセス プロセス socket socket
socket()システムコール int socket(int family, int type, int proto) AF_INET IPv4プロトコル AF_INET6 IPv6プロトコル AF_LOCAL UNIX Domain Socket AF_ROUTE 経路制御ソケット 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 TCP SOCK_DGRAM UDP SOCK_RAW なし
初期状態 クライアント プロセス サーバ プロセス Port A Port B Port C ホストA ホストB IP Address: xx.xx.xx.xx. IP Address: xx.xx.xx.xx.
Socketを開いた状態 Socketを開く クライアント プロセス サーバ プロセス Port A Port B Port C ホストA IP Address: xx.xx.xx.xx. IP Address: xx.xx.xx.xx.
bindした状態 Proto LocalAdddress ForeignAddress State TCP *.A *.* Closed クライアント プロセス サーバ プロセス Port A Port B Port C ホストA ホストB IP Address: xx.xx.xx.xx. IP Address: xx.xx.xx.xx.
Stream example (TCP) Server socket() bind() Client listen() socket() accept() Block until connect Connection Establishmt. connect() 暗黙にbind() Data (request) send() recv() Process request Data (reply) send() recv()
Datagram example (UDP) Server socket() Client bind() socket() recvfrom() bind() Block until Data from client sendto() Data (request) Process request Data (reply) sendto() recvfrom()
Datagram example2 (UDP) Server socket() Client bind() socket() recvfrom() bind() Block until Data from client connect() Data (request) send () Process request Data (reply) sendto() recv ()
sockaddr_in構造体 ソケットの情報 アドレス … 32bit ポート番号 … 16bit プロトコルファミリー … AF_INET… 7 15 31 長さ protocol Port番号 アドレス unused unused
sockaddr構造体 ソケットの情報を一般化した形 ソケットを使った通信のためのテンプレート 利用するプロトコルに依存しない 共通: 長さ・プロトコルファミリ(AF_XXX) 7 15 31 長さ protocol unused unused unused unused
キャスト ある変数・構造体を無理やり違う型の変数や構造体として扱う方法 変数を使う時に扱いたい型をカッコで括る (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()
ネットワーク・バイト・オーダ 1 2 2 1 1 2 3 4 4 3 2 1 Network Byte Order CPUアーキテクチャによって、バイトの並びが違う 一般にBig Endian(sparc等)とLittle Endian(Intel等)の二つ ネットワーク上に流すバイト順を統一しなくてはならない Big Endianに統一 htons()/htonl()/ntohs()/ntohl()を利用 リトルエンディアン ビッグエンディアン 16ビット整数 (short) 1 2 2 1 32ビット整数 (long) 1 2 3 4 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; /*IP addressのサイズ*/ u_char sin_family; /*AF_INET etc*/ u_short sin_port; /*port num*/ struct in_addr sin_addr; /*IP address*/ char sin_zero[8]; /*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の順番が逆