Perl - Socket编程

什么是套接字?

Socket是一种在不同进程之间创建虚拟双工连接的Berkeley UNIX机制.随后将其移植到每个已知的操作系统,以便在跨不同OS软件运行的地理位置的系统之间进行通信.如果不是套接字,系统之间的大多数网络通信永远不会发生.

仔细观察;网络上的典型计算机系统根据其上运行的各种应用程序接收和发送信息.此信息被路由到系统,因为为其指定了唯一的IP地址.在系统上,此信息将提供给相关应用程序,这些应用程序可以侦听不同的端口.例如,因特网浏览器在端口80上侦听从Web服务器接收的信息.我们也可以编写可以监听和发送/接收特定端口号信息的自定义应用程序.

现在,让我们总结一下套接字是一个IP地址和一个端口,启用通过网络发送和接收数据的连接.

为了解释上面提到的套接字概念,我们将以Perl为例进行客户端 - 服务器编程.要完成客户端服务器体系结构,我们必须执行以下步骤 :

创建服务器

  • 使用 socket 调用创建套接字.

  • 使用bind调用将套接字绑定到端口地址。

  • 使用 listen 调用侦听端口地址处的套接字.

  • 使用接受电话接受客户连接.

创建客户

  • 使用 socket 调用创建套接字.

  • 使用 connect 电话将(套接字)连接到服务器.

下图显示了客户端和服务器用于彼此通信的完整序列调用 :

Perl Socket

服务器端套接字呼叫

socket()调用

socket()调用是建立网络连接的第一个调用是创建套接字.此调用具有以下语法 :

socket( SOCKET, DOMAIN, TYPE, PROTOCOL );


上述调用创建一个SOCKET,其他三个参数是整数,它们应具有以下TCP/IP连接值.

  • DOMAIN 应为PF_INET.您的计算机上可能有2个.

  • TYPE 应为SOCK_STREAM,用于TCP/IP连接.

  • PROTOCOL 应该是(getprotobyname('tcp'))[2] .它是通过套接字说出TCP等特定协议.

所以服务器发出的套接字函数调用会像这个 :

use Socket     # This defines PF_INET and SOCK_STREAM

socket(SOCKET,PF_INET,SOCK_STREAM,(getprotobyname('tcp'))[2]);


bind()调用

socket()调用创建的套接字在绑定到a之前是无用的主机名和端口号.服务器使用以下 bind()函数指定它们将接受来自客户端的连接的端口.

bind( SOCKET, ADDRESS );


这里SOCKET是socket()调用返回的描述符,ADDRESS是一个包含三个元素&minus的套接字地址(用于TCP/IP);

  • 地址系列(对于TCP/IP,即AF_INET,系统可能为2).

  • 端口号(例如21).

  • 计算机的互联网地址(例如10.12.12.168).

由于服务器使用bind(),因此不需要知道自己的地址,因此参数列表如下所示 :

use Socket        # This defines PF_INET and SOCK_STREAM

$port = 12345;    # The unique port used by the sever to listen requests
$server_ip_address = "10.12.12.168";
bind( SOCKET, pack_sockaddr_in($port, inet_aton($server_ip_address)))
   or die "Can't bind to port $port! \n";


或die 子句非常重要,因为如果服务器在没有未完成连接的情况下死亡,则该端口不会立即重复使用,除非使用 setsockopt()函数使用选项SO_REUSEADDR.这里 pack_sockaddr_in()函数用于将端口和IP地址打包成二进制格式.

listen()调用

如果这是一个服务器程序,则需要在指定端口上发出 listen()的呼叫来监听,即等待传入的请求.此调用具有以下语法 :

listen( SOCKET, QUEUESIZE );


上述调用使用socket()调用返回的SOCKET描述符,QUEUESIZE是同时允许的未完成连接请求的最大数量.

accept()调用

如果这是服务器程序,则需要发出对 access()函数的调用以接受传入连接.此调用具有以下语法 :

accept( NEW_SOCKET, SOCKET );


接受调用接收socket()函数返回的SOCKET描述符,并在成功完成后,返回一个新的套接字描述符NEW_SOCKET,用于客户端和服务器.如果access()调用失败,那么它返回FLASE,它在我们最初使用的Socket模块中定义.

通常,accept()用于无限循环.一旦一个连接到达,服务器就会创建一个子进程来处理它或自己服务,然后回去监听更多的连接.

while(1) {
   accept( NEW_SOCKET, SOCKT );
   .......
}


现在所有与服务器相关的电话都结束了,让我们看一个电话将被客户要求.

客户端套接字呼叫

connect()调用

如果你要准备客户端程序,然后首先你将使用 socket()调用来创建一个套接字,然后你必须使用 connect()调用来连接到服务器.您已经看过socket()调用语法,它将与服务器socket()调用类似,但这里是 connect() call&minus的语法;

connect(SOCKET,ADDRESS);


这里SCOKET是客户端发出的socket()调用返回的套接字描述符,ADDRESS是类似于 bind 的套接字地址调用,但它包含远程服务器的IP地址.

$port = 21;    # For example, the ftp port
$server_ip_address = "10.12.12.168";
connect( SOCKET, pack_sockaddr_in($port, inet_aton($server_ip_address)))
   or die "Can't connect to port $port! \n";


如果您成功连接到服务器,那么您可以使用SOCKET描述符开始将命令发送到服务器,否则您的客户端将通过提供错误而出现消息.

客户端 - 服务器示例

以下是使用Perl套接字实现简单客户端 - 服务器程序的Perl代码.这里服务器侦听传入的请求,一旦建立连接,它只是回复来自服务器的微笑.客户端读取该消息并在屏幕上打印.让我们看看它是如何完成的,假设我们的服务器和客户端在同一台机器上.

创建服务器的脚本

#!/usr/bin/perl -w
# Filename : server.pl

use strict;
use Socket;

# use port 7890 as default
my $port = shift || 7890;
my $proto = getprotobyname('tcp');
my $server = "localhost";  # Host IP running the server

# create a socket, make it reusable
socket(SOCKET, PF_INET, SOCK_STREAM, $proto)
   or die "Can't open socket $!\n";
setsockopt(SOCKET, SOL_SOCKET, SO_REUSEADDR, 1)
   or die "Can't set socket option to SO_REUSEADDR $!\n";

# bind to a port, then listen
bind( SOCKET, pack_sockaddr_in($port, inet_aton($server)))
   or die "Can't bind to port $port! \n";

listen(SOCKET, 5) or die "listen: $!";
print "SERVER started on port $port\n";

# accepting a connection
my $client_addr;
while ($client_addr = accept(NEW_SOCKET, SOCKET)) {
   # send them a message, close connection
   my $name = gethostbyaddr($client_addr, AF_INET );
   print NEW_SOCKET "Smile from the server";
   print "Connection recieved from $name\n";
   close NEW_SOCKET;
}


要以后台模式运行服务器,请在Unix上发出以下命令提示符 :

$perl sever.pl&


创建客户的脚本

!/usr/bin/perl -w
# Filename : client.pl

use strict;
use Socket;

# initialize host and port
my $host = shift || 'localhost';
my $port = shift || 7890;
my $server = "localhost";  # Host IP running the server

# create the socket, connect to the port
socket(SOCKET,PF_INET,SOCK_STREAM,(getprotobyname('tcp'))[2])
   or die "Can't create a socket $!\n";
connect( SOCKET, pack_sockaddr_in($port, inet_aton($server)))
   or die "Can't connect to port $port! \n";

my $line;
while ($line = <SOCKET>) {
   print "$line\n";
}
close SOCKET or die "close: $!";


现在让我们在命令提示符下启动我们的客户端,命令提示符将连接到服务器并读取服务器发送的消息并在屏幕上显示如下内容 :

$perl client.pl
Smile from the server


注意 : 如果您以点表示法提供实际IP地址,则建议在客户端和服务器中以相同格式提供IP地址,以避免混淆.