前へ << UDP を使ってみよう (1) | UDP を使ってみよう (3) >> 次へ |
socket(SOCKET, PF_INET, SOCK_DGRAM, 0); bind(SOCKET, pack_sockaddr_in(7000, INADDR_ANY)); recv(SOCKET, $buf, 10000, 0);
UDP | TCP | 意味 |
---|---|---|
socket (SOCK_DGRAM) | socket (SOCK_STREAM) | ソケット生成 |
bind | bind | ソケットとポートと結合 |
- | listen | ポート受け付け開始 |
- | accept | コネクションを取得 |
recv | read (<SOCKET> で1行読み込み) | データ読み込み |
一方クライアント側は以下のような手順になります。
socket(SOCKET, PF_INET, SOCK_DGRAM, 0); $iaddr = inet_aton('targethost'); $sock_addr = pack_sockaddr_in(7000, $iaddr); send(SOCKET, "hoge", 0, $sock_addr);
UDP | TCP | 意味 |
---|---|---|
socket (SOCK_DGRAM) | socket (SOCK_STREAM) | ソケット生成 |
inet_aton pack_sockaddr_in |
inet_aton pack_sockaddr_in |
ソケットアドレス構造体を作成 |
- | connect | サーバに接続 |
send | write (print SOCKET "...") | データ送信 |
% ./udp-server-1.plとして起動します。すると UDP のポート 7000 に届いたデータを表示します。
次に (サーバ側を実行させたまま) 同じマシン上で
% ./udp-client-1.pl localhost 7000としてクライアントを起動します。
クライアントが起動すると、引数で指定した localhost:7000 に対して、
Hello 1 Hello 2 Hello 3 Hello 4 : Hello 99998 Hello 99999 Hello 100000と、「Hello 送信回数」というデータを 10万回サーバに送信します。 サーバは
受信データ=Hello 1 (受信回数 1) 受信データ=Hello 2 (受信回数 2) 受信データ=Hello 3 (受信回数 3) 受信データ=Hello 4 (受信回数 4) :と受信したデータを表示しはじめます。普通に考えると、このまま 100,000 個のデータを受信し、最後は
: 受信データ=Hello 99999 (受信回数 99999) 受信データ=Hello 100000 (受信回数 100000)となるように思えるのですが、UDP ですから そうはなりません。 FreeBSD 4.4-RELEASE で、クライアントとサーバを同じマシン上で実行した結果、 以下のようになりました。
: 受信データ=Hello 512 (受信回数 512) 受信データ=Hello 513 (受信回数 513) 受信データ=Hello 1624 (受信回数 514) 受信データ=Hello 1625 (受信回数 515) : 受信データ=Hello 98533 (受信回数 3616) 受信データ=Hello 98534 (受信回数 3617) 受信データ=Hello 98535 (受信回数 3618)513 回目までは正しく送信できているのですが、 514〜1623 まではデータがサーバに届いていません。 その後も、89449〜97804、97871〜98469、98536〜100000 は紛失し、結局届いたのは 100,000 分の 3,618。 到達率 3.6%、つまり
1: #!/usr/local/bin/perl -w 2: 3: # $Id: udp-client-1.pl,v 1.1 2002/02/17 10:19:18 68user Exp $ 4: 5: use Socket; # Socket モジュールを使う 6: 7: use Errno; # Errno 定数モジュールを使う 8: 9: if ( @ARGV != 2 ){ 10: print "引数で [接続先ホスト名] [接続先ポート番号] を指定して下さい。\n"; 11: exit; 12: } 13: 14: # 接続先ホスト名を取得 15: $host = shift @ARGV; 16: 17: # 接続先ポート番号を取得 18: $port = shift @ARGV; 19: 20: # ホスト名を、IP アドレスの構造体に変換 21: $iaddr = inet_aton($host) 22: or die "$host は存在しないホストです。\n"; 23: 24: # ポート番号と IP アドレスを構造体に変換 25: $sock_addr = pack_sockaddr_in($port, $iaddr); 26: 27: # ソケット生成 28: socket(SOCKET, PF_INET, SOCK_DGRAM, 0) 29: or die "ソケットを生成できません。\n"; 30: 31: # send する回数 32: $num_of_senddata = 100000; 33: 34: # ENOBUFS が発生した回数 35: $num_of_enobufs = 0; 36: 37: for ( $i=1 ; $i<=$num_of_senddata ; ){ 38: if ( ! send(SOCKET, "Hello $i", 0, $sock_addr) ){ 39: # エラーが発生した 40: 41: if ( $! == Errno::ENOBUFS ){ 42: # 送信バッファがいっぱい (ENOBUFS) ならリトライ 43: 44: $num_of_enobufs++; 45: next; 46: 47: } else { 48: # ENOBUFS 以外なら終了 49: die "send に失敗しました ($i)。$!\n"; 50: } 51: } 52: $i++; 53: } 54: 55: print "$host:$port に対して send を $num_of_senddata 回実行しました。\n"; 56: print "ENOBUFS の発生回数 $num_of_enobufs\n";
1: #!/usr/local/bin/perl -w 2: 3: # $Id: udp-server-1.pl,v 1.1 2002/02/17 10:19:18 68user Exp $ 4: 5: use Socket; # Socket モジュールを使う 6: 7: $port = 7000; # ポート番号は 7000 番 8: 9: # ソケット生成 10: socket(SOCKET, PF_INET, SOCK_DGRAM, 0) 11: or die "ソケットを生成できません。\n"; 12: 13: bind(SOCKET, pack_sockaddr_in($port, INADDR_ANY)); 14: 15: $recv_count = 0; 16: 17: while (1){ 18: recv(SOCKET, $buf, 10000, 0); 19: $recv_count++; 20: print "受信データ=$buf (受信回数 $recv_count)\n"; 21: 22: # スピード調整のためのウェイト 23: # select(undef, undef, undef, 0.01); 24: }
1: #!/usr/local/bin/perl -w 2: 3: # $Id: tcp-client-vs-udp.pl,v 1.1 2002/02/17 10:19:18 68user Exp $ 4: 5: use Socket; 6: 7: if ( @ARGV != 2 ){ 8: print "引数で [接続先ホスト名] [接続先ポート番号] を指定して下さい。\n"; 9: exit; 10: } 11: 12: $host = shift @ARGV; 13: $port = shift @ARGV; 14: 15: $iaddr = inet_aton($host) || die "$!"; 16: $sock_addr = pack_sockaddr_in($port, $iaddr) || die "$!"; 17: socket(SOCKET, PF_INET, SOCK_STREAM, 0) || die "$!"; 18: connect(SOCKET, $sock_addr) || die "$!"; 19: 20: $num_of_senddata = 100000; 21: 22: for ( $i=1 ; $i<=$num_of_senddata ; $i++ ){ 23: print SOCKET "Hello $i\n" || die "$!"; 24: } 25: 26: print "$host:$port に対して、データを $num_of_senddata 回送信しました。\n";
1: #!/usr/local/bin/perl -w 2: 3: # $Id: tcp-server-vs-udp.pl,v 1.1 2002/02/17 10:19:18 68user Exp $ 4: 5: use Socket; 6: 7: $port = 7000; 8: 9: socket(SOCKET, PF_INET, SOCK_STREAM, 0) or die "$!"; 10: setsockopt(SOCKET, SOL_SOCKET, SO_REUSEADDR, 1) || die "$!"; 11: bind(SOCKET, pack_sockaddr_in($port, INADDR_ANY)) || die "$!"; 12: listen(SOCKET, SOMAXCONN) || die "$!"; 13: accept(NEWSOCK, SOCKET) || die "$!"; 14: 15: while (<NEWSOCK>){ 16: chomp; 17: $recv_count++; 18: print "受信データ=$_ (受信回数 $recv_count)\n"; 19: }
前へ << UDP を使ってみよう (1) | UDP を使ってみよう (3) >> 次へ |
ご意見・ご指摘は Twitter: @68user までお願いします。