Socket是在不同进程之间创建虚拟双工连接的Berkeley UNIX机制。后来将其移植到每个已知的OS上,以使跨不同OS软件运行的地理位置的系统之间进行通信。如果不使用Socket,系统之间的大多数网络通信将永远不会发生。
仔细看看;网络上的典型计算机系统会根据网络上运行的各种应用程序的需要来接收和发送信息。该信息被路由到系统,因为为其指定了唯一的IP地址。在系统上,此信息被提供给在不同端口上侦听的相关应用程序。例如,互联网浏览器在端口80上侦听从Web服务器接收的信息。我们也可以编写我们的自定义应用程序,这些应用程序可以在特定端口号上侦听和发送/接收信息。
现在,让我们总结一下,Socket是一个IP地址和一个端口,使连接能够通过网络发送和接收数据。
为了解释上面提到的Socket概念,我们将以使用Perl进行客户端-服务器编程为Example。要完成客户端服务器体系结构,我们必须执行以下步骤-
使用 socket 调用创建Socket。
使用 bind 调用将Socket绑定到端口地址。
使用 listen 调用来监听端口地址处的Socket。
使用 accept 调用接受客户端连接。
使用 socket 调用创建Socket。
使用 connect 调用将(Socket)连接到服务器。
下图显示了客户端和服务器相互通信使用的完整呼叫顺序-
socket()调用是建立网络连接并创建Socket的第一个调用。该调用具有以下语法-
socket( SOCKET, DOMAIN, TYPE, 协议 );
上面的调用创建了一个SOCKET,其他三个参数是整数,对于TCP/IP连接应具有以下值。
DOMAIN 应该是PF_INET。在您的计算机上大概是2。
TYPE 对于TCP/IP连接应为SOCK_STREAM。
协议
应该为(getprotobyname('tcp'))[2] 。通过Socket使用的是特定协议,例如TCP。因此,服务器发出的Socket函数调用将如下所示:
use Socket # This defines PF_INET and SOCK_STREAM socket(SOCKET,PF_INET,SOCK_STREAM,(getprotobyname('tcp'))[2]);
通过socket()调用创建的Socket在将它们绑定到主机名和端口号之前是无用的。服务器使用以下 bind()函数来指定其将接受来自客户端的连接的端口。
bind( SOCKET, ADDRESS );
这里的SOCKET是socket()调用返回的描述符,而ADDRESS是包含三个元素的Socket地址(对于TCP/IP)-
地址族(对于TCP/IP,这是AF_INET,在您的系统上可能是2个)
端口号(例如21)
计算机的Internet地址(例如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";
or die 子句非常重要,因为如果服务器在没有出色连接的情况下死亡,那么除非您使用 setsockopt()函数使用optionsSO_REUSEADDR,否则端口将无法立即重用。在这里, pack_sockaddr_in()函数用于将端口和IP地址打包为二进制格式。
如果这是服务器程序,则需要在指定端口上发出对 listen()的调用,以监听即等待传入的请求。该调用具有以下语法-
listen( SOCKET, QUEUESIZE );
上面的调用使用了socket()调用返回的SOCKET描述符,而QUEUESIZE是同时允许的最大未完成连接请求数。
如果这是服务器程序,则需要发出对 access()函数的调用以接受传入的连接。该调用具有以下语法-
accept( NEW_SOCKET, SOCKET );
接受调用接收socket()函数返回的SOCKET描述符,成功完成后,将返回新的Socket描述符NEW_SOCKET,以用于客户端和服务器之间的所有将来通信。如果access()调用失败,则它将返回FLASE,该FLASE在我们最初使用的Socket模块中定义。
通常,accept()在无限循环中使用。一旦一个连接到达,服务器要么创建一个子进程来处理它,要么自己提供服务,然后返回以监听更多连接。
while(1) { accept( NEW_SOCKET, SOCKT ); ....... }
现在,与服务器有关的所有呼叫均已结束,让我们看一看客户端需要的呼叫。
如果要准备客户端程序,则首先将使用 socket()调用来创建Socket,然后必须使用 connect()调用来连接到服务器。您已经看过socket()调用语法,它将与服务器socket()调用类似,但这是 connect()调用的语法-
connect( SOCKET, ADDRESS );
这里的SCOKET是由客户端发出的socket()调用返回的Socket描述符,而ADDRESS是类似于 bind 调用的Socket地址,除了它包含远程服务器的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描述符将命令发送到服务器,否则您的客户端将通过显示一条错误消息而退出。
以下是使用PerlSocket实现简单的客户端-服务器程序的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地址,以免造成混淆。
祝学习愉快!(内容编辑有误?请选中要编辑内容 -> 右键 -> 修改 -> 提交!)