首页 | 社区 | 博客 | 招聘 | 文章 | 新闻 | 下载 | 读书 | 代码
亲,您未登录哦! 登录 | 注册

用Delphi在客户端执行Unix主机命令

打印文章

分享到:
问题的提出
在一个客户/服务器模式的网络环境中,数据库(Informix)服务器建立在SCO Unix 5.05上,同时,有若干台运行Windows 95/98的工作站。需要解决的问题是:如何在客户端执行一段程序,然后由服务器来完成数据库中数据的处理并进行转发,即由客户端来控制远端服务器的命令执行。它的实际意义在于服务器可能位于几公里甚至几百公里以外的地方。
解决的方法和思路
由于SCO Unix服务器提供了多种网络服务,如WWW、FTP、MAIL、GOPHER、TELNET等,我们可以在客户端通过TELNET访问远端主机,登录成功后,由服务器直接执行来自客户端的命令集,从而实现对服务器上的数据进行处理的目的。
本文客户端开发语言选择Delphi,当然,VC++也是此类编程的利器,尤其是VC++对WINSOCK的封装极大地减轻了程序员的工作量,可以说在Windows 95/98平台上它是网络软件开发的最佳选择。而Delphi最大的长处则在于对数据库的支持能力上,同时,它的组件也非常丰富。
众所周知,TCP/IP协议是Internet上的标准协议集,也是目前网络操作系统所支持的主要协议之一。TELNET实际上是TCP/IP的应用层协议,属于高层协议之一,这个协议提供了一个相对一般的、双向的通信服务。TELNET连接实际上就是一个TCP连接,一旦这种连接建立成功,那么,用户的计算机将作为远端主机的终端来使用而不管主机的物理位置是在同一间办公室内,或是千里之外。TELNET协议除了人们通常所知道的网络虚拟终端外,还有另外一个重要的概念:协商任选项机制。这种机制允许服务器和客户程序之间协商选项,TELNET的某些任选项是已经分配好的(如表1所示)。
任选项 意义
0 二进制传送
1 回送
2 GO AHEAD
3 AMS协商
5 状态
6 时标
7 远程受控传送
8 输出行结束
9 输出页大小
10 输出回车描述
24 终端类型
…… ……
表1
本文对任选项做了如下定义:
  const F_IAC=255;
  DO协商
  const F_DO=253;
  DO NOT协商
  const F_DONT=254;
  WILL 协商
  const F_WILL=251;
  WILL NOT协商
  const F_WONT=252;
  const F_GOAHEAD=3;
  const F_ECHO=1;
编程实现
为了能将解决问题的方法说得更清楚,本文对实现功能进行了简化,即客户程序登录主机之后,由Unix主机执行一个来自客户端的命令:MKDIR /TMP/FANG。命令执行完后,可以在服务器上查看执行结果。当然,在实际编程环境下不会仅仅是这样一条简单的命令,但基本原理是相同的。程序的测试界面如图1所示:

图1 测试界面
在Form1中有一个非可视组件TClientSocket,它位于组件面板的Internet页上。Delphi利用这个组件对TCP/IP进行了封装。
程序的部分代码如下:
procedure TForm1.Button1Click(Sender: TObject);
begin
 if ClientSocket1.Active then ClientSocket1.Active := False;
  if InputQuery(‘连接至:', ‘地址:', Server) then
   if Length(Server) > 0 then
    with ClientSocket1 do
    begin
     Address := Server;
     Active := True;
end;
end;
procedure TForm1.readfromhost(Sender:TObject;
Socket: TCustomWinSocket);
begin
 loginsend:=False;
 passsend:=False;
 count:=Socket.ReceiveBuf(InBuffer,High
(InBuffer));
 m_count:=0;
 while (m_count begin
ch:=InBuffer[m_count];
if (ch=char(F_IAC)) then
begin
m_count:=m_count+1;
cmd:=InBuffer[m_count];
   if((cmd=char(F_DO))or(cmd=char
(F_WILL))or(cmd=char(F_DONT))or(cmd=char
(F_WONT))) then
begin
m_count:=m_count+1;
nOpt:=InBuffer[m_count];
if((nOpt=char(F_GOAHEAD))or
(nOpt=char(F_ECHO))) then
begin
if(cmd=char(F_DO)) then
begin
reply[0]:=char(F_IAC);
reply[1]:=char(F_WILL);
reply[2]:=nOpt;
Socket.SendBuf(reply,Length(reply));
end;
if(cmd=char(F_WILL)) then
  begin
reply[0]:=char(F_IAC);
reply[1]:=char(F_DO);
reply[2]:=nOpt;
Socket.SendBuf(reply,
Length(reply));
end;
end;
if((nOpt<>char(F_GOAHEAD))or(nOpt<>char(F_ECHO))) then
begin
if(cmd=char(F_DO)) then
begin
reply[0]:=char(F_IAC);
reply[1]:=char(F_WONT);
reply[2]:=nOpt;
Socket.SendBuf(reply,
Length(reply));
end;
if(cmd=char(F_WILL)) then
begin
reply[0]:=char(F_IAC);
reply[1]:=char(F_DONT);
reply[2]:=nOpt;
Socket.SendBuf(reply,
Length(reply));
end;
end;
end;
end; //end F_IAC
if(ch<>char(F_IAC)) then
begin
m_string:=m_string+ch;
end;
m_count:=m_count+1;
  end;
  //假设编程者知道Unix的LOGIN和PASSWORD
  if(Length(m_string)>0) then
   begin
while ((Pos(‘login:',m_string)>0)and(not
loginsend)) do
begin
cmdtounix:=‘root'+#10+#13;
code:=Socket.SendBuf(cmdtounix,6);
loginsend:=True;
end;
while ((Pos(‘Password:',m_string)>0)and(not passsend)) do
begin
cmdtounix:=‘root'+#13+#10;
code:=Socket.SendBuf(cmdtounix,6);
passsend:=True;
m_string:=‘';
end;
if ( Pos(‘jcy:/#>',m_string)>0) then
begin
cmdtounix:=‘mkdir /tmp/fang'+#
13+#10;
code:=Socket.SendBuf(cmdtounix,
Length(cmdtounix));
if code>0 then
begin
ClientSocket1.Active:=False;
Close;
end;
end;
   end;
  end;
end;
小 结

虽然这段程序并不复杂,但它是网络软件编程的一个基本思路。需要指出的是,在某些场合,程序员也可以根据自己的需要定义一些协议,以便解决问题。当然,自己定义的协议应用范围可能会很窄,只能在某个系统或程序中使用。

本栏文章均来自于互联网,版权归原作者和各发布网站所有,本站收集这些文章仅供学习参考之用。任何人都不能将这些文章用于商业或者其他目的。( Pfan.cn )

编程爱好者论坛

本栏最新文章