| 前へ << 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 までお願いします。