采用套接字的TCP通信

ZDNet软件频道 时间:2002-04-15 作者:ZDNET CHINA 特稿 |  我要评论()
本文关键词:PERL TCPIP
本文向读者讲解一个具体的TCP通信例程,也就是所谓的“套接字(socket)编程”,该例程采用Perl语言编写,实现了基本的客户机/服务器应用程序功能。

在本系列的前一篇文章里,我对TCP协议、协议目标以及针对TCP操作和控制TCP的一些UNIX系统命令进行了阐述。接下来我将通过本文向读者讲解一个具体的TCP通信例程,也就是所谓的“套接字(socket)编程”,该例程采用PERL语言编写,实现了基本的客户机/服务器应用程序功能。

当心缓冲溢出

所谓缓冲溢出(buffer overflow)是经常被非法利用的一种常见安全漏洞。正是因为这一问题才导致大量的应用程序不得不经常进行安全升级。在编写你的服务器程序代码的时候,客户程序可能会向服务器发送一个字符串,在这种情况下就可能发生缓冲溢出。假如你在把这种字符串收到缓冲内的时候设计不仔细,采用了固定长度的缓冲大小,那么恶意客户程序可以用以上的字符串溢出缓冲,结果就可能对服务器系统实现非法访问甚至可以运行自己的非法代码。某些高级编程语言具有内置的缓冲溢出防护机制,比如动态地重置变量大小或者采取其他办法等。

创建服务器

创建服务器程序要完成以下任务:

  • 创建一个套接字。
  • 把这个套接字绑定到某个端口。
  • 侦听该端口同时接受客户连接。

我们会创建一个简单的服务器程序,在键入w命令的时候响应请求,w命令会显示系统的登录成员以及他们目前的行为、系统时间、和计算机运行时间以及平均负载等。用这个程序管理多台服务器的时候会觉得非常方便,这样你就可以建立cron任务(定时操作)访问每一个系统、报告系统的状态。程序代码在调用参数的时候不做任何检查,只需要待观察的端口号即可,在没有指定端口的情况下默认为9876。清单A 即是这一服务器程序的代码。

运行程序:
[stew@moe stew]$ ./socket-serv.pl
Using port: 9876


这个小小的服务器程序启动后等待客户连接,按下[Ctrl]C键即可关闭服务器进程。你可以用Telnet而非编写客户程序来测试该程序,如清单B所示。

现在就让我们仔细分析下清单A中的代码。最初的4行代码决定是否指定端口;如果没有指定端口就采用默认分配的端口号9876。通常,你自己编写的服务器需要采用大于1024的端口号,因为1024及其以下的端口都定义为供常用服务所使用。AF_INETSOCK_STREAM 分别指地址和套接字类型,它们的值在/usr/include/bits/socket.h (Linux 2.4源代码目录)中定义。

$sockaddr 变量定义绑定调用所采用的地址和端口格式。它由一个无符号短整型(S)、一个网络顺序(n)、4个ASCII字符(a4)以及8个零字节(x8)组成。然后,我们获取要采用的协议号,显示状态行,定义服务器地址。

select(SOCK) 所在行的代码指定SOCK 作为默认的输出文件句柄,其缓冲设置为每次写入或者打印的时候清空。

接下来的三行代码创建套接字SERVER,绑定套接字,然后开始在这个套接字上执行侦听,其最大客户队列设置为5。

最后的无限循环只负责对以上套接字的访问等待,同时用w命令的输出结果响应客户。

创建客户程序

虽然我们完全可以用telnet代替专门编写客户端程序进行演示,不过我们还是在这里用PERL语言编写了一个客户程序。为此,我们要在程序中完成以下工作:

  • 创建一个套接字。
  • 把这个套接字连接到运行以上服务器程序的远程计算机。
  • 捕获服务器输出结果并在标准输出(stdout )上打印出来然后退出。

清单C 即是客户程序代码,而清单D 则显示了执行客户程序之后的示例输出结果。

客户程序的代码对以上的服务器程序来说实在是太理想了。变量是预先定义好的,服务器端口地址也设好了,到socket的连接也建立了。再有,我们用SOCK 文件句柄作为stdout 并把缓冲设置为每次写入和打印的时候清空。然后我们从套接字连接中读取服务器输入信息并在stdout,上打印输出结果,最后程序退出。

你可以用PERLIO::Socket 模块简化以上的程序代码。这样做可以显著地减少套接字的设置代码。实际上你的系统上已经采用过这样的模块了,比如你可以通过CPAN执行以下命令:
PERL -MCPAN -e 'install IO::Socket'

采用socket模块,服务器代码可以修改成清单E的样子,客户代码则改为清单F

正如你看的那样,IO::Socket 包含了设置套接字连接的各个细节。

退出

好了,现在你就写出了一对TCP客户机-服务器应用程序。在以上程序中,你可以方便地修改服务器循环中的代码改变服务器输出,同时你还可以编写其他代码增强客户程序或者服务器程序的功能。比如,在服务器端你可以:

  • 添加日志功能,在系统日志里记录系统访问。
  • 添加解析引擎让服务器响应不同类型的客户请求。
  • 重新编写服务器程序,采用发起父子进程的方式响应多个客户请求。

我希望以上的简单示例程序能让你了解系统之间UNIX套接字通信的基本技术。正因为TCP/IP的前瞻性设计使之足以处理相当程度的交互,与此同时所需要的代码却并不算多,比如你在使用PERL编写此类程序时就很容易明白。

责任编辑:超凡

百度大联盟认证黄金会员Copyright© 1997- CNET Networks 版权所有。 ZDNet 是CNET Networks公司注册服务商标。
中华人民共和国电信与信息服务业务经营许可证编号:京ICP证010391号 京ICP备09041801号-159
京公网安备:1101082134