ソケット
元に戻る。
ソケットは外部コンピュータとの間でTCP/IPやUDP通信を行うための
インターフェースである。
ソケット通信はファイルと同様にソケットをオープンし、
通信を行い、ソケットをクローズする。
| 名称 | 番号 | 目的 |
|---|
| FTP | 21 | ファイル転送 |
| Telnet | 23 | 遠隔操作 |
| SMTP | 25 | メール送信 |
| HTTP | 80 | ホームページ |
| POP3 | 110 | メール受信 |
-
TCPクライアント
-
1) socketでソケットをオープン
2) connectでリモートアドレスに接続
3) send, recvまたはprint,read,<>でデータの送受
4) closeでソケットをクローズ
-
TCPサーバ
-
1) socketでソケットをオープン
2) bindでソケットにローカルアドレスを割り当てる
3) listenでソケットが接続を受け付けることをシステムに知らせる
4) acceptでクライアントからの接続を受け付ける
5) connect要求があればソケットを自動的にオープンする
6) send, recvまたはprint,read,<>でデータの送受
7) closeでソケットをクローズ
8) 5)へ戻る
-
UDPクライアント
-
1) socketでソケットをオープン
2) bindでソケットにローカルアドレスを割り当てる
3) send(宛先を指定)、recvでデータの送受
4) closeでソケットをクローズ
-
UDPサーバ
-
1) socketでソケットをオープン
2) bindでソケットにローカルアドレスを割り当てる
3) recvでデータの受信
4) sendで返事をする
5) 3)へ戻る
以下のソケット例文は中島 靖著
Perl徹底活用インターネットダイレクトアクセス
p.40 に掲載されているプログラムである。
#!/usr/bin/perl
use Socket;
# コマンドラインからポート番号を得る。
$port= shift || 9999;
# プロトコル番号を得る。
$proto=getprotobyname('tcp');
# listenするソケットをオープンする。
socket(ListenSock,PF_INET,SOCK_STREAM,$proto)
or die("ソケットがオープン出来ない:$!\n");
# bindする
bind(ListenSock,sockaddr_in($port,INADDR_ANY))
or die("ソケットがbindできない:$!\n");
# listenする
listen(ListenSock,SOMAXCON);
# 待機し、接続要求があれば日時を返す
print "ポート番号:$port で待機開始\n";
while($sockaddr=accept(ConnectSock,ListenSock)){
select(ConnectSock); $|=1; select(STDOUT);
# クライアントからポート番号、IP、ホスト名を得る
my($port,$ipaddr)=sockaddr_in($sockaddr);
my $name = gethostbyaddr($ipaddr,AF_INET);
$ipaddr=inet_ntoa($ipaddr);
print "$name($ipaddr)のポート番号$portから接続\n";
# 日時を返す。
print ConnectSock "Hello $name, now ",scalar localtime, "\n";
close(ConnectSock);
}
# 終了
close(ListenSock);
exit;
fork()を利用して多重受け付けを行う。
#!/usr/bin/perl
# ソケットTCPサーバプログラム(並行処理)
use Socket;
# コマンドラインからポート番号を得る。
$port= shift || 9999;
# プロトコル番号を得る。
$proto=getprotobyname('tcp');
# listenするソケットをオープンする。
socket(ListenSock,PF_INET,SOCK_STREAM,$proto)
or die("ソケットがオープン出来ない:$!\n");
# 複数接続設定
setsockopt(ListenSock,SOL_SOCKET,SO_REUSEADDR,1)
or die("ソケットオプションが設定出来ない:$!\n");
# bindする
bind(ListenSock,sockaddr_in($port,INADDR_ANY))
or die("ソケットがbindできない:$!\n");
# listenする
listen(ListenSock,5);
# 待機し、接続要求があれば日時を返す
print "ポート番号:$port で待機開始\n";
while( $sockaddr = accept(ConnectSock,ListenSock) )
{
my $pid;
# クライアントからポート番号、IP、ホスト名を得る
my($port,$ipaddr)=sockaddr_in($sockaddr);
my $name = gethostbyaddr($ipaddr,AF_INET);
$ipaddr=inet_ntoa($ipaddr);
print "$name($ipaddr)のポート番号$portから接続\n";
# forkして並行処理
if( !defined($pid = fork) )
# fork できない
{ print "fork できない: $!\n"; }
elsif( $pid )
# 親プロセス
{ print "子プロセス($pid)開始\n"; }
else
# 子プロセス
{
# 待機用プロセスは閉じる
close(ListenSock);
# 日時を返す
print ConnectSock "Hello $name, now ",scalar localtime, "\n";
# 子プロセス終了
close(ConnectSock);
exit;
}
# 親プロセスは接続を終了し、待機ループに戻る
close(ConnectSock);
}
# 終了
close(ListenSock);
exit;
#!/usr/bin/perl
use Socket;
# コマンドラインからホスト名とサービス名を得る。
$host = shift || 'localhost';
$port= shift || 9999;
# プロトコル番号を得る。
$port=getservebyname($port,'tcp') if($port =~ /\D/);
die("指定されたポートがない\n") unless($port);
# ホスト名->IPアドレス、IPアドレスとポート番号->ソケットアドレス
$ipaddr=inet_aton($host) or die("$hostが見つからない\n");
$sockaddr=sockaddr_in($port,$ipaddr);
# プロトコル番号を得る。
$proto=getprotobyname('tcp');
# ソケットをオープンし、接続する。
socket(SOCK,PF_INET,SOCK_STREAM,$proto)
or die("ソケットがオープンできない:$!\n");
connect(SOCK,$sockaddr)
or die("ソケットが接続できない:$!\n");
# サーバからのデータを全て表示する
while(<SOCK>){
print;
}
# ソケットを閉じて終了する。
close(SOCK) or die("ソケットがクローズできない:$!\n");
exit;
#!/usr/bin/perl
use Socket;
# コマンドラインからポート番号を得る。
$port= shift || 9999;
# プロトコル番号を得る。
$proto=getprotobyname('udp');
# listenするソケットをオープンする。
socket(SOCK,PF_INET,SOCK_DGRAM,$proto)
or die("ソケットがオープン出来ない:$!\n");
# bindする
bind(SOCK,sockaddr_in($port,INADDR_ANY))
or die("ソケットがbindできない:$!\n");
# 待機し、接続要求があれば日時を返す
print "ポート番号:$port で待機開始\n";
while($sockaddr=recv(SOCK,$_,1000,0)){
# クライアントからポート番号、IP、ホスト名を得る
my($port,$ipaddr)=sockaddr_in($sockaddr);
my $name = gethostbyaddr($ipaddr,AF_INET);
$ipaddr=inet_ntoa($ipaddr);
print "$name($ipaddr)のポート番号$portから接続\n";
# 日時を返す。
send(SOCK,"Hello $name, now ".(scalar localtime)."\n",0,$sockaddr)
}
# 終了
close(SOCK);
exit;
#!/usr/bin/perl
use Socket;
use Sys::Hostname;
# コマンドラインからホスト名とサービス名を得る。
$host = shift || 'localhost';
$port= shift || 9999;
# プロトコル番号を得る。
$port=getservebyname($port,'udp') if($port =~ /\D/);
die("指定されたポートがない\n") unless($port);
# ホスト名->IPアドレス、IPアドレスとポート番号->ソケットアドレス
$ipaddr=inet_aton($host) or die("$hostが見つからない\n");
$sockaddr=sockaddr_in($port,$ipaddr);
# プロトコル番号を得る。
$proto=getprotobyname('udp');
# ソケットをオープンし、接続する。
socket(SOCK,PF_INET,SOCK_DGRAM,$proto)
or die("ソケットがオープンできない:$!\n");
# ローカルアドレスをbindする
bind(SOCK,sockaddr_in(0,scalar gethostbyname(hostname())));
# 空パケットを送る。
send(SOCK,0,0,$sockaddr);
# サーバからのパケットを受信する。
recv(SOCK,$_,1000,0);
print;
# ソケットを閉じて終了する。
close(SOCK) or die("ソケットがクローズできない:$!\n");
exit;
accept(NEWSOCKET,GENERICSOCKET)
クラインアントからの接続要求を待ち、NEWSOCKETをオープンする。
失敗すると偽を返す。
GENERICSOCKETはsocket()でオープンされ、bind()でサーバに
アロケートされた受信ソケットアドレス。
bind(SOCKET,SOCKADDR)
ソケットSOCKETにローカルアドレスSOCKADDRを割り当てる。
SOCKADDRはIP+ポート番号をパックした値で、sockaddr_in()で
作成する。失敗すると偽を返す。
connect(SOCKET,SOCKADDR)
ソケットSOCKETにリモートアドレスSOCKADDRを接続する。
失敗すると偽を返す。
gethostbyaddr(IPADDR,ADDRTYPE)
IPアドレスから情報を得る。
gethostbyname(NAME)
ホスト名から情報を得る。
getpeername(SOCKET)
ソケットSOCKETの接続リモートアドレスを返す。
プロトコル番号を得る。TCPまたはUDPである。
TCPなら、
$proto=getprotobyname('tcp');
UDPなら、
$proto=getprotobyname('udp');
getservbyname Port, Proto
getservbyname(3)と同等の作業をする。
Port番号ににプロトコールを指定する。
例:
$port = shift || 2345; # 適当なポート番号
If ($port =~ /\D/) {$port = getservbyname($port, 'tcp')}
die "No port" unless $port;
getsockname(SOCKET)
ソケットSOCKETの接続ローカルアドレスを返す。
getsockopt(SOCKET,LEVEL,OPTNAME)
ソケットSOCKETのオプションの値を返す。
listen(SOCKET,QUESIZE)
ソケットSOCKETがQUESIZE個受け付けるように設定する。
成功すれば1、失敗すれば0を返す。
QUESIZEを最大値に設定するにはSOMAXCONNを指定する。
recv(SOCKET,SCALAR,LENGTH,FLAGS)
SOCKETからLENGTHバイトのメッセージを受信し、SCALARに記録する。
成功すると送信元のアドレスを、失敗すれば未定義を返す。
send(SOCKET,MSG,FLAGS[,TO])
SOCKETへMSGを送信する。成功すると送信バイト数、
失敗すれば未定義を返す。
UDPでは送信先TOを指定する。
setsockopt(SOCKET,LEVEL,OPTNAME,OPTVAL)
SOCKETにオプション名、値を設定する。
shutdown(SOCKET,HOW)
HOW値に従ってSOCKETをクローズする。
HOW値は、0なら受信、1なら送信、2なら両方を指定する。
socket(SOCKET,PROTOCOLFAMILY,TYPE,PROTOCOL)
SOCKETをオープンする。
PROTOCOLFAMILYは、1でローカルドメイン、2でインターネットドメイン。
TYPEはTCPでは、SOCK_STREAM、UDPではSOCK_DGRAMを使用する。
TCP/SERVER側、ソケットオープン
socket(ListenSock,PF_INET,SOCK_STREAM,$proto)
or die("ソケットがオープン出来ない:$!\n");
TCP/CLIENT側、ソケットオープン
socket(SOCK,PF_INET,SOCK_STREAM,$proto)
or die("ソケットがオープンできない:$!\n");
UDP/SERVER側、ソケットオープン
socket(SOCK,PF_INET,SOCK_DGRAM,$proto)
or die("ソケットがオープン出来ない:$!\n");
UDP/CLIENT側、ソケットオープン
socket(SOCK,PF_INET,SOCK_DGRAM,$proto)
or die("ソケットがオープンできない:$!\n");