Perl socket programming tutorial
Socket programming in perl can be done using the low level socket functions or the IO::Socket module.The IO::Socket module provides an object-oriented interface to the socket functions.
In this tutorial we are going to use the low level socket functions.
10年积累的成都网站制作、网站建设经验,可以快速应对客户对网站的新想法和需求。提供各种问题对应的解决方案。让选择我们的客户得到更好、更有力的网络服务。我虽然不认识你,你也不认识我。但先网站设计后付款的网站建设流程,更有山城免费网站建设让你可以放心的选择与我们合作。
实例1:连接百度端口80
[root@dou Socket]# cat 1.pl
#!/usr/bin/perl -w
use strict;
# The socket function can be used to create a socket.In the following code example we shall create a tcp socket.
use Socket;
my $proto = getprotobyname('tcp'); # get the tcp protocol
# Create a socket handle(descriptor)
socket(SOCKET,AF_INET,SOCK_STREAM,$proto) or die "cant create socket:$!\n";
# Connecting to a remote server
my $remote = 'www.baidu.com';
my $port = 80;
my $iaddr= inet_aton($remote) or die "unable to resolve hostname: $remote\n";
my $paddr = sockaddr_in($port,$iaddr); # socket address structure
connect(SOCKET,$paddr) or die "connect failed : $!\n";
print "Connected to $remote on port $port\n";
# Close a socket
close SOCKET,
exit(0);
In the above example we connected to baidu.com on port 80.
Before the connect function is called the sockaddr_in structure has to be setup.
The sockaddr_in structure stores the information about the remote address,
address type and port number. The inet_aton function converts a hostname/ip to
ip address in long number format.
[root@dou Socket]# cat 1.pl
#!/usr/bin/perl -w
use strict;
# The socket function can be used to create a socket.In the following code example we shall create a tcp socket.
use Socket;
use Encode;
my $proto = getprotobyname('tcp'); # get the tcp protocol
# Create a socket handle(descriptor)
socket(SOCKET,AF_INET,SOCK_STREAM,$proto) or die "cant create socket:$!\n";
# Connecting to a remote server
my $remote = 'www.baidu.com';
my $port = 80;
my $iaddr= inet_aton($remote) or die "unable to resolve hostname: $remote\n";
my $paddr = sockaddr_in($port,$iaddr); # socket address structure
connect(SOCKET,$paddr) or die "connect failed : $!\n";
print "Connected to $remote on port $port\n";
# Send data
# Once connected it's time to start communication by sending some data.The send function can be used for this.
# Send some data to remote server - the HTTP GET command
send(SOCKET,"GET / HTTP/1.0\n\n",0) or die "send failed:$!\n";
# Receive reply from server - perl way of reading from stream.
# Can also do recv(SOCKET,$msg,2000,0).
while(my $line =
# $line = encode_utf8($line);
$line = encode("utf-8",decode("gbk",$line));#(translate gbk code to utf-8 code)
print "$line\n";
}
# Close a socket
close SOCKET,
exit(0);
Revise
In the above examples we learned the following socket operations.
1. Create a socket
2. Connect to remote server/system.
3. Send data
4. Receive a reply
The socket program we wrote above is called a client.
A client connects to a remote server for exchange of information/data.
Apart from the client the other type of socket program we are going to write is called a server.
The server serves data to clients connecting to it.
So lets move on to the next section to do some server programming in perl.
Server
The basic steps for making a server are :
1. Create a socket
2. Bind to a local address and local port
3. Listen for incoming connections
4. Accept incoming connections
5. Communicate the with the newly connected client - send and receive data.
So a server does not connect out to a system, instead it waits for incoming connections.
We have already seen how to create a socket.
So the next task to make a server would be to bind the socket.
The bind function can be used for this task.
Lets take a quick example
[root@dou Socket]# cat server.pl
#!/usr/bin/perl -w
use strict;
use Socket;
$| = 1;
#create a socket handle(descriptor)
socket(SERVER,AF_INET,SOCK_STREAM,(getprotobyname('tcp'))[2]) or die "cant create socket :$!\n";
#bind to local port 10000
my $port = 10000;
#the socket is bound to port 10000 and address "any".After bind the socket has to be put in listen mode.
bind(SERVER,sockaddr_in($port,INADDR_ANY)) or die "bind failed:$!\n";
# listening the incoming connections
listen(SERVER,10);
print "Server is now listening...\n";
# After calling listen,the socket is ready to accept incoming connections using the accept function.
This shall be done in a loop so that the program can accept connections again and again.
#accept incoming connections and talt to clients
while(1) {
my $addrinfo = accept(TALK,SERVER);
my($port,$iaddr) = sockaddr_in($addrinfo);
my $clienthost = gethostbyaddr($iaddr,AF_INET);
print "Connection accepted from $clienthost:$port\n";
# send some message to the client
print TALK "hello client how are you\n";
close TALK;
}
#close the socket
close SERVER;
exit(0);
[root@dou socket]# telnet localhost 10000
Trying 127.0.0.1...
Connected to localhost.localdomain (127.0.0.1).
Escape character is '^]'.
hello client how are you
Connection closed by foreign host.
指定server的ip地址:
[root@dou Socket]# cat 2.pl
#!/usr/bin/perl -w
use strict;
use Socket;
$| = 1;
#create a socket handle(descriptor)
socket(SERVER,AF_INET,SOCK_STREAM,(getprotobyname('tcp'))[2]) or die "cant create socket :$!\n";
#bind to local port 10000
my $port = 10000;
my $server = "192.168.0.6";
my $iaddr = inet_aton($server);
my $paddr = sockaddr_in($port,$iaddr);
#the socket is bound to port 10000 and address "any".After bind the socket has to be put in listen mode.
bind(SERVER,$paddr) or die "bind failed:$!\n";
# listening the incoming connections
listen(SERVER,10);
print "Server is now listening...\n";
# After calling listen,the socket is ready to accept incoming connections using the accept function. This shall be done in a loop so that the program can accept connections again and again.
#accept incoming connections and talt to clients
while(1) {
my $addrinfo = accept(TALK,SERVER);
my($port,$iaddr) = sockaddr_in($addrinfo);
my $clienthost = gethostbyaddr($iaddr,AF_INET);
print "Connection accepted from $clienthost:$port\n";
# send some message to the client
print TALK "hello client how are you\n";
close TALK;
}
#close the socket
close SERVER;
exit(0);
高级技术:
Asynchronouse I/O
Multiple clients can be handled by asynchronous event driven I/O. IO::Select can be used for this.
[root@dou Socket]# cat iosocket.pl
#!/usr/bin/perl -w
use strict;
use Socket;
use IO::Select;
$| = 1;
my $socket;
my $servtoclient;
#create a socket handle(descriptor)
my $proto = getprotobyname('tcp');
socket($socket,PF_INET,SOCK_STREAM,$proto) or die "create socket failed:$!\n";
#bind to local port
my $port = 10001;
my $server = "192.168.0.6";
my $iaddr = inet_aton($server);
my $paddr = sockaddr_in($port,$iaddr);
bind($socket,$paddr) or die "bind failed:$!\n";
#listen incoming connections
listen($socket,10);
print "Server $server on port $port is now listening ...\n";
#accept incoming connections and talk to clients
my $select = IO::Select->new();
$select->add($socket);
while(1) {
my @ready = $select->can_read(0);
foreach my $select_io(@ready) {
#new connection read
if($select_io == $socket) {
my $clientinfo = accept($servtoclient,$socket);
my($clientport,$clientiaddr) = sockaddr_in($clientinfo);
my $clienthost = gethostbyaddr($clientiaddr,AF_INET);
print "Connection accepted from $clienthost : $clientport\n";
# send some message to the client
send($servtoclient,"Hello client[$clienthost]! Nice to meet you !\n",0);
$select->add($servtoclient);
}
# existing client read
else {
chop(my $clientinput = <$select_io>);
chop($clientinput);
if ($clientinput =~ /quit/i) {
$select->remove($select_io);
$select_io->close;
}else {
print "Received -- $clientinput\n";
# send reply back to client
send($select_io,"OK : $clientinput\n",0);
}
}
}
}
#close the socket
close $socket;
exit(0);
server端运行命令
[root@dou Socket]# perl iosocket.pl &
[1] 3580
[root@dou Socket]# Server 192.168.0.6 on port 10001 is now listening ...
[root@dou Socket]#
客户端访问:下面是服务器返回的信息
[root@dou ~]# telnet 192.168.0.6 10001
Trying 192.168.0.6...
Connected to dou.perl.gov (192.168.0.6).
Escape character is '^]'.
Hello client[dou.perl.gov]! Nice to meet you !
同时server端也返回信息:
[root@dou Socket]# Connection accepted from dou.perl.gov : 42617
客户端开始发送信息:
ls---->send
OK : ls ---->receive
hello---->send
OK : hello ---->receive
hello world---->send
OK : hello world ---->receive
同时server端也返回信息:
Received -- ls
Received -- hello
Received -- hello world
下面是更经典的iosocket程序:
#!/usr/bin/perl -w
use strict;
use Socket;
use IO::Select;
$| = 1;
my $path = "/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin";
my @paths = split(/:/,$path);
my $hit = 0;
my $command;
my @lines;
my $line;
my $socket;
my $servtoclient;
my $reply;
#create a socket handle(descriptor)
my $proto = getprotobyname('tcp');
socket($socket,PF_INET,SOCK_STREAM,$proto) or die "create socket failed:$!\n";
#bind to local port
my $port = 10001;
my $server = "192.168.0.6";
my $iaddr = inet_aton($server);
my $paddr = sockaddr_in($port,$iaddr);
bind($socket,$paddr) or die "bind failed:$!\n";
#listen incoming connections
listen($socket,10);
print "Server $server on port $port is now listening ...\n";
#accept incoming connections and talk to clients
my $select = IO::Select->new();
$select->add($socket);
while(1) {
my @ready = $select->can_read(0);
foreach my $select_io(@ready) {
if($select_io == $socket) {
my $clientinfo = accept($servtoclient,$socket);
my($clientport,$clientiaddr) = sockaddr_in($clientinfo);
my $clienthost = gethostbyaddr($clientiaddr,AF_INET);
print "Connection accepted from $clienthost : $clientport\n";
send($servtoclient,"Hello client[$clienthost]! Nice to meet you !\n",0);
$select->add($servtoclient);}
else {
while(chop(my $clientinput = <$select_io>)) {
chop($clientinput);
$clientinput =~ s/^[ \t]*//;
if ($clientinput =~ /quit/i) {
$select->remove($select_io);
$select_io->close;
last; # (跳出while循环jump out the loop of while)
#close $socket;
#exit 0;
}else {
@lines = split(/[ ]/,$clientinput);
chomp($command = $lines[0]);
foreach my $dir (@paths) {
search($dir);
if ($hit == 1) {
last; # (跳出foreach循环jump out the loop of foreach)
}
}
if ($hit != 0) {
send($select_io, "Command is [$command]:\n",0);
$reply = `$clientinput`;
#send reply back to client
send($select_io,"$reply",0);
} else {
send($select_io,"you enter string [$clientinput]\n",0);
}
}
}
}
}
}
#close the socket
close $socket;
exit(0);
sub search {
my $dir = shift;
opendir(DIR,"$dir") or die "cant open dir:$dir:$!\n";
my @files = readdir(DIR);
closedir(DIR);
foreach my $file (@files) {
next if ($file =~ m/^\.$/ || $file =~ m/^\.\.$/);
if ("$file" eq "$command") {
$hit += 1;
return(0);
} else {
$hit = 0;
}
}
}
服务器端:
[root@dou Socket]# perl 7.pl &
[1] 3641
[root@dou Socket]# Server 192.168.0.6 on port 10001 is now listening ...
[root@dou Socket]# Connection accepted from dou.perl.gov : 33965
客户端:
[root@dou ~]# telnet 192.168.0.6 10001
Trying 192.168.0.6...
Connected to dou.perl.gov (192.168.0.6).
Escape character is '^]'.
Hello client[dou.perl.gov]! Nice to meet you !
ls
Command is [ls]:
1.pl
1.py
2.pl
44.pl
4.pl
5.pl
6.pl
7.pl
aaa
client.pl
ht.pl
iosocket.pl
iosocket.pl.orig
open_client.pl
server.pl
tk.pl
hostname
Command is [hostname]:
dou.perl.gov
hostname
Command is [hostname]:
dou.perl.gov
quit
Connection closed by foreign host.
上述程序的说明:
1)服务器端perl 7.pl &将程序至于后台运行
2)客户端使用telnet进行测试
3)可以输入linux中常用的命令:比如:ls hostname ifconfig eth0等。并且命令的前面可以有多个空格或者tap键。
4)该程序通过搜索系统$PATH路径来确定输入的string是否是一个命令,如果是系统命令的话将$hit的值加1,程序
通过控制$hit的值来觉得是否输出命令的结果,还是单纯的字符串。