ソケットによる複数平行アクセスをするには
[上に]
[前に]
[次に]
同期
2000/03/05(日) 23:22:43
perlで他のサーバーにあるファイルを読むのにソケットを使っています。
WIN95, ActivePerl version 5.005_03 Build 522
これを複数平行して実行するにはどうしたら良いのでしょうか?
一つだけなら
*前処理
while(<S>){
print O $_;
}
*後処理
のようにやる訳ですがこれを
*前処理
while(データがある間){
$s1=<S1>;print O1 $s1;
$s2=<S2>;print O2 $s2;
$s3=<S3>;print O3 $s3;
}
*後処理
のようにしたいと思っているのです。
問題となるのがサーバーからのデータ読み込みで
すべてのサーバーに対するアクセスがスムーズなら良いのですが
例えばS2のサーバーが遅いと次のS3サーバーにアクセスしに行かないのです。
そこで直接<S2>のようにデータを読みに行くのでなく
データがあるかを確認してから読めばいいのではと思ったのですが
そこでつまづいてしまいました。
同時平行でなく
*前処理
while(<S1>){
print O1 $_;
}
*後処理
*前処理
while(<S2>){
print O2 $_;
}
*後処理
のようにすれば良いという意見もあると思いますが
これでもS2が遅いとS3の処理に進みませんよね。
そこでIE5の同期のように平行して出来たらS2が遅くても
取りあえずS1とS3の処理が出来て良いかなと考えたのですが・・・。
気まぐれ
2000/03/06(月) 00:43:44
作ったこと無いんで確証は無いですが・・・
子供(子プロセス)を作って、親で動作をコントロールするとか。
# でも作った以上は責任を持ってコントロールしないとサーバーが
# 異常動作するかも
↓ここが参考になるかもしれません。
http://X68000.startshop.co.jp/~68user/
ユニオン
2000/03/06(月) 05:25:10
はじめまして、ユニオンといいます。
プロセスやスレッドを新たに作らずにやりたいのなら
select()を使ってみてはいかがでしょうか?
(デフォルトの出力を変更するものではなくてシステムコールのほう)
Perlでselectを使ったことがないので実例は示せませんが、参考までに
B-Cus
2000/03/06(月) 07:52:52
他にもソケットをノンブロッキングモードにするとか、
use Socket;
recv(SOCK,$buf,1024,MSG_PEEK);
ってのもあるでよ。
同期
2000/03/09(木) 23:01:25
select()の使用法が良く判らなかったので
fcntl()でノンブロッキングにしてrecv(MSG_PEEK)でデータチェックする
以下のようなプログラムを作って試したのですが
Your vendor has not defined Fcntl macro F_SETFL
となってしまいました。(^^;
引数の指定法が悪いのでしょうか?
test.cgiはN秒スリープしながらデータを出力するプログラムで
これ自体の動作は問題ありません。
use Fcntl;
use Socket;
$server = "localhost";
$url = "/cgi/test.cgi";
$addr = (gethostbyname($server))[4];
$name = pack("S n a4 x8", 2, 80, $addr);
socket(S, 2, 1, 0);
$ret = connect(S, $name);
print "connect[$ret]\n";
fcntl(S, F_SETFL, O_NONBLOCK);
select(S); $| = 1; select(stdout);
print S "GET $url HTTP/1.0\n\n";
$done = 0;
while (!$done)
{
recv(S, $buf, 1024, MSG_PEEK);
if($buf ne "")
{
$buf = <S>;
if($buf eq "")
{
$done = 1;
}
else
{
print "[$buf]\n";
}
}
sleep(1); print ".\n"; # 動作確認用の表示
}
close(S);
B-Cus
2000/03/10(金) 02:52:33
> select()の使用法が良く判らなかったので
use IO::Socket;
use IO::Select;
@servers=qw(www.goo.ne.jp www.yahoo.co.jp www.wakusei.ne.jp);
$selecter=IO::Select->new;
$port = 80;
foreach $server ( @servers ){
$sock = IO::Socket::INET->new("$server:$port");
$selecter->add($sock);
$sock2host{$sock} = "$server:$port";
$message = "GET / HTTP/1.0\nHost: $server\n\n";
print $sock "$message";
$sock->flush();
}
$last_sock = $#servers+1;
while ($last_sock){
($active_socks) = IO::Select->select($selecter,undef,undef,undef);
foreach $sock (@$active_socks){
$len = read($sock,$buf,1024);
if ( $len ){
$buf =~ s/^(.{20}).*/$1/s;
$buf =~ s/^/ /mg;
print "read ${len}bytes from $sock2host{$sock} $buf....\n";
} else {
print "fin $sock2host{$sock}\n";
$selecter->remove($sock);
$last_sock--;
}
}
}
同期
2000/03/10(金) 21:30:20
[[解決]]
これです。まさにこういう動作をさせたかったのです。
参考にさせて頂きます。
どうもありがとうございます。(^^)
[上に]
[前に]
[次に]