Se ha denunciado esta presentación.
Utilizamos tu perfil de LinkedIn y tus datos de actividad para personalizar los anuncios y mostrarte publicidad más relevante. Puedes cambiar tus preferencias de publicidad en cualquier momento.

60分でわかるソケットプログラミング

17.901 visualizaciones

Publicado el

ソケットプログラミングの基礎の基礎。C言語ができて、UNIXのシステムコール
プログラミングができる人が対象です。

  • Follow the link, new dating source: ❶❶❶ http://bit.ly/369VOVb ❶❶❶
       Responder 
    ¿Estás seguro?    No
    Tu mensaje aparecerá aquí
  • Dating for everyone is here: ❶❶❶ http://bit.ly/369VOVb ❶❶❶
       Responder 
    ¿Estás seguro?    No
    Tu mensaje aparecerá aquí
  • I have barely snored at all! My girlfriend was starting to put pressure on me to have an operation to stop my snoring, but to be totally honest I was scared stiff. I've heard some horror stories and there was no way I wanted to take on that risk. Then I found your website and since putting your techniques into practice I have barely snored at all. My girlfriend can't believe how effective this has been. ▲▲▲ http://t.cn/AigiCT7Q
       Responder 
    ¿Estás seguro?    No
    Tu mensaje aparecerá aquí

60分でわかるソケットプログラミング

  1. 1. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 60分でわかるソケットプログラミン グ 60分でわかるソケットプログラミン グ 木本雅彦 <kimoto@soum.co.jp> <kimoto@ohnolab.org> 株式会社創夢 第三開発部 シニアプロジェクトマネージャ 初版:2010年4月作成、改定版:2015年3月作成
  2. 2. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 創夢とはどういう会社か UNIXとTCP/IPネットワークに強い会社 全員がUNIXに詳しい 全員がIPに詳しい ということは → 全社員がネットワークプログラミングくら い出来るよね!? ということで、60分レクチャーです 1/47
  3. 3. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 この発表での前提条件 C言語でのプログラミングはできる system call programming file I/O basics TCP/IPの基礎は理解している OSI階層モデル IPアドレス、ヘッダの構造など 2/47
  4. 4. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 IPというプロトコルについて IP = InternetProtocol はじめに: ホストにはIPアドレスがついているらしいぜ (以下略。知らない人は自力で勉強してください) 3/47
  5. 5. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 TCPとUDPというプロトコル TCP: Transmission Control Protocol 送達確認(ACK)の利用による信頼性のある通信 輻輳制御による「フェアな」通信量の制御 UDP: User Datagram Protocol 信頼性のない通信 パケット単位でデータを投げるだけ 4/47
  6. 6. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 port番号 TCP, UDPで用いる通信口の番号 符号なし16bit 通信相手のアプリケーションを同定する 5/47
  7. 7. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 well-known portとephemeral port well-known port 代表的なサービスに割り当てられた番号 0 - 1023 IANAが管理している ephemeral port 使い捨てポート RFCでのdynamic port: 49152〜65535 Linuxの実装: 32768〜61000 古いBSDの実装: 1024〜4999 6/47
  8. 8. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 一応IPv6について、ひとこと 次世代インターネットプロトコル といいつつ、すでに実用化されている IPアドレスが128bitに拡張されたという一点がもっとも 重要 アドレスの自動設定 マルチキャストの積極的な利用 7/47
  9. 9. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 UNIXのプロセス間通信 pipe 双方向パイプ FIFO 共有メモリ(SYSV由来) セマフォ(SYSV由来) signal socket(BSD由来) 8/47
  10. 10. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 socket 4.2BSDで導入されたTCP/IPの抽象化および実装 通信路の片方の末端を指し示す ファイルデスクリプタで表される →ネットワーク通信をファイルI/Oと同様に記述できる 9/47
  11. 11. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 余談:socketという敗北 4.2BSDでsocketが導入されたのは、従来のUNIXの ようにファイルシステム上にネットワークI/Oをマッピングで きなかったため 主に性能上の理由 これが後々まで影響を及ぼす 例:jailやDocker(コンテナ型仮想化)において、ネットワークの制約の ための枠組みが別途必要になる 10/47
  12. 12. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 サーバクライアントモデル ネットワーク通信のモデル化の一つ vs Peer to Peer サーバ サービスを提供する側 要求を待って処理した結果を返す クライアント サービスを利用する側 サーバに接続し要求を出し処理結果を受け取る 11/47
  13. 13. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 サーバクライアントの通信の流れ 12/47
  14. 14. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 サーバ側の処理の流れ socket(2)でsocketを作る bind(2)でsocketに待受アドレスとポートを指定する listen(2)で待受開始 select(2)で複数ソケットのイベントループを回す 接続があったらaccept(2)で受信して通信用ソケット を得る read(2), write(2)で送受信 13/47
  15. 15. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 socket(2) ソケットを作成するsystemcall ソケットを表すファイルデスクリプタを返す int socket(int domain, int type, int protocol); domain: PF_INET, PF_INET6, .... type: SOCK_STREAM, SOCK_DGRAM, .. protocol: IPPROTO_IP, ... 14/47
  16. 16. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 bind(2) ソケットに名前をつける 名前とは: IPアドレス ポート番号 int bind(int s, const struct sockaddr *addr, socklen_t addrlen); 第2引数で名前=アドレスを指定する 15/47
  17. 17. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 listen(2) 接続を待ち受ける int listen(int s, int backlog); backlogは最大保留数 16/47
  18. 18. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 accept(2) TCPの接続を受けつけ、dynamic portを割り当てる int accept(int s, struct sockaddr * restrict addr, socklen_t * restrict addrlen); 17/47
  19. 19. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 イベントドリブン型プログラミング 外部からのイベントを契機に処理を駆動するプログラミ ングモデル イベント待ち受け イベント受信 ディスパッチ if文の羅列による分岐 ハンドラ/ジャンプテーブル タイマ処理と合わせて擬似スレッドも実現できる 18/47
  20. 20. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 select(2)システムコール fd_set: fdの集合(ビットマップ) read/write/errでチェックするfdを指定(複数可) selectで待つ fd_setにイベントが発生したsocketのfdがセットされる 19/47
  21. 21. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 典型的なselect loop sock = accept(....); for (;;) { FD_ZERO(&fds); FD_SET(sock, &fds); result = select(getdtablesize(),&fds,NULL,NULL, NULL); if (FD_ISSET(sock,&fds)) { **** read from socket ****** } } 20/47
  22. 22. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 多重待受のselect loop listenしているポートもselectの対象にする listen(lsock, ....); for (;;) { FD_ZERO(&fds); FD_SET(lsock, &fds); if (sock >= 0) {FD_SET(sock, &fds);} result = select(getdtablesize(),&fds,NULL,NULL, NULL); if (FD_ISSET(lsock,&fds)) { sock = accept(lsock, ...); continue; } if (sock >= 0 && FD_ISSET(sock,&fds)) { **** read from socket ****** } } 21/47
  23. 23. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 クライアント側の処理の流れ socket(2)でsocketを作る bind(2)でsocketに通信先アドレスとポートを指定す る connect(2)で接続する read(2), write(2)で送受信 22/47
  24. 24. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 connect(2) ソケット経由で接続開始する int connect(int s, const struct sockaddr *name, socklen_t namelen); 23/47
  25. 25. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 readn, writen socketからの読み書きは1度のread/writeで完了す る保証がない 指定した長さが完了するまでread/writeを繰り返す 必要がある readn() / writen() 関数を使う cf. Stevens' UNIX Network Programming ただしブロックしてしまうので注意が必要 24/47
  26. 26. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 sample code of writen: int writen(int fd,char *ptr,size_t size) { int i; while(size > 0) { if ((i = write(fd,ptr,size)) < 0) return i; ptr += i; size -= i; } return size; } 25/47
  27. 27. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 UDPとTCPのプログラミングの違い UDPクライアントはbindしなくていい(してもいい) UDPクライアントはconnectしなくていい(してもいい) UDPはsendto(2)/recvfrom(2)で相手を指定して 送受信できる connectしていればread/writeでもよい 26/47
  28. 28. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 文字列からIPアドレスを得る古い方法 inet_aton IPアドレスの文字列を数値に変換する gethostbyname ホスト名からIPアドレスを得る gethostbyname2 AddressFamilyを指定してホスト名からIPアドレスを得る getservbyname サービス名からポート番号を得る 27/47
  29. 29. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 IPアドレスを得る新しい方法 getaddrinfoを使ったクライアントの例 getaddrinfo(peer, buf, &hints, &res0)); s = -1; for (res = res0; res; res = res->ai_next) { s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s < 0) continue; connect(s, res->ai_addr, res->ai_addrlen); break; } 28/47
  30. 30. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 ソケットが使っているアドレスを得る方法 getsockname ソケットの自分側のsockaddrを得る getpeername ソケットの相手側のsockaddrを得る 29/47
  31. 31. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 poll, libevent selectを使った実装は重くなる fdごとにif文でチェックするため poll(struct pollfd fds[], nfds_t nfds, int timeout); チェックのコストが低い libevent イベントハンドラを記述するだけ socket以外のイベントも監視できる 30/47
  32. 32. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 タイマ処理 タイマ割り込みによる定期的な処理 alarm(unsigned int seconds); setitimer(int which, .....); selectのtimeoutを用いてタイマ処理を実装すること もある 31/47
  33. 33. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 selectとsignal signalを受信してselectを抜ける場合があるので注 意 タイマ割り込みなど selectがエラーで終了したら、errnoの値を調べる必要がある do { result = select(getdtablesize(),&fds,&wfds,NULL, &tv2); } while((result < 0) && (errno == EINTR)); 32/47
  34. 34. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 bind: address already in use bindしようとしたら、他のプロセスが既にportを使って いる プロセスが異常終了した後、サーバーを再起動すると 出ることがある setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (char *)&sockopt, sizeof(sockopt)); 33/47
  35. 35. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 setsockopt socketの動作を設定する SO_REUSEADDR enables local address reuse SO_REUSEPORT enables duplicate address and port bindings SO_KEEPALIVE enables keep connections alive SO_DONTROUTE enables routing bypass for outgoing messages SO_LINGER linger on close if data present ..... 34/47
  36. 36. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 non blocking socket 複数のサーバに同時に非同期にconnectしたい場合 サーバとクライアントを兼ねている場合 e.g. bgpd, P2P application connectでblockしない f = fcntl(s, F_GETFL); fcntl(s, F_SETFL, f | O_NONBLOCK); 35/47
  37. 37. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 自分のIPアドレスを得る方法 ダメな例 gethostname() → gethostbyname() 多くの場合は127.0.0.1になる 実用的な例 UDP socketを作る 遠くのアドレスに向けてconnectする getsocknameする ただし経路がない場合はこの方法は使えない 36/47
  38. 38. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 struct sockaddr 異なるプロトコルのアドレスを格納するための構造体 struct sockaddr { unsigned char sa_len; /* total length */ sa_family_t sa_family; /* address family */ char sa_data[14]; /* actually longer; address value */ }; OSの違いによるsa_lenの有無に注意が必要 領域を確保するためには、sockaddr_storageを使う 37/47
  39. 39. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 UNIX domain socket いわゆる名前付きパイプ 単一ホスト内の通信に使う PF_UNIX or PF_LOCAL bindする時にパス名を使う 実際にファイルが作成される e.g. try, ls -la /tmp/ 38/47
  40. 40. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 socketpair(2) 名前なしパイプ 連結した二つのsocketを返す パイプと同様に使える 双方向に通信可能 39/47
  41. 41. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 コネクション切断を識別する selectでreadableなのにreadすると0byte → connectionが切れている この処理をしないとselect loopが回り続けるので注 意 40/47
  42. 42. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 inetd: Internet super daemon クライアントからの待ち受けをinetdが行う 接続があったら、プロセスに引き渡す socketがプロセスの標準入出力に割り当てられる 標準入出力のI/Oだけでサーバが記述できる 41/47
  43. 43. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 daemon化するということ daemon化には決まった手順がある 2度forkした後、途中のprocessを終了させ、initの子供になる 標準入出力を/dev/nullに割り当てる 制御端末を切り離す 通常はroot directoryに移動する see daemon(3) 42/47
  44. 44. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 raw socket IPペイロードを直接入出力できる ICMP, OSPFなどで使われている see ping root権限が必要 よって、pingはsetuidされている 43/47
  45. 45. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 BPF: Berkley Packet Filter 生のEthernet Frameを送受信できる /dev/bpf?をopenする ioctlでインタフェースを割り当てる readするとBPFヘッダがついてくる 複数のパケットが読める場合もある writeするとそのままEthernet I/Fに出て行く read時にfilterを記述できる filterは「状態マシン」 44/47
  46. 46. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 Packet Socket : LinuxでL2のパケットを 送受信する方法 PF_PACKET, SOCK_RAWを指定してsocketを作 る L2のパケットを直接送受信できる インタフェースはbind()で割り当てる 簡単なフィルタはあるが、主にPPPoE用と思われる 送受信はread()/write()で行う sock = socket(PF_PACKET, SOCK_RAW, 0); 45/47
  47. 47. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 パケット構造設計の注意点 独自でバイナリ形式のプロトコルを設計する場合 バージョン番号はつけること パケットの長さは先頭部分で明示したほうがよい メモリ領域の確保のため ヘッダとボディとに分けるとよい ボディはTLV(Type, Length, Value)でいいかもしれない 46/47
  48. 48. (c) Masahiko KIMOTO, Ph.D. - http://www.earthlight.jp/ Powered by Rabbit 2.1.6 Where should you start from? inetd 1 session server and client multi-session server and more... 47/47

×