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.
实例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: $remoten";
my $paddr = sockaddr_in($port,$iaddr); # socket address structure
connect(SOCKET,$paddr) or die "connect failed : $!n";
print "Connected to $remote on port $portn";
# 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,$paddr) or die "connect failed : $!n";
print "Connected to $remote on port $portn";
# 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.0nn",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 = <SOCKET>) {
#?????? $line = encode_utf8($line);
??????? $line = encode("utf-8",decode("gbk",$line));#(translate gbk code to utf-8 code)
??????? print "$linen";
}
# 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,(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:$portn";
??????? # send some message to the client
??????? print TALK "hello client how are youn";
??????? 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,(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,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,AF_INET);
??????? print "Connection accepted from $clienthost:$portn";
??????? # send some message to the client
??????? print TALK "hello client how are youn";
??????? 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,$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 : $clientportn";
??????????????????????? # 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 -- $clientinputn";
??????????????????????????????? # send reply back to client
??????????????????????????????? send($select_io,"OK : $clientinputn",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,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,AF_INET);
??????????????????????? print "Connection accepted from $clienthost : $clientportn";
??????????????????????? send($servtoclient,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的值来觉得是否输出命令的结果,还是单纯的字符串。 ?