Linux 版 (精华区)

发信人: netiscpu (说不如做), 信区: Linux
标  题: Client/Server计算的乐趣
发信站: 哈工大紫丁香 (Mon May 17 13:29:22 1999), 转信

"Linux公报... 让Linux更富魅力!"

---------------------------------------------------------------------------

-----

Client/Server 计算的乐趣

By David Nelson   译者 arnzh <arnzh@ynmail.com>

---------------------------------------------------------------------------

-----

    嗨!想要找点乐是吗?试试客户/服务器计算吧。就象是通过两个中间拉紧了绳子

的罐头合子说话一般,只不过升级到了计算机上。LINUX提供了你需要的所有工具。其

实你早就使用了客户/服务器计算了,列如:Netscape,Telnet,Ftp等等。要编写你自

己的Client/Server应用也是很容易的,可能也是很有用的。     Client/Server 计算

通过网络把两个不同的程序(客户和服务器)连在一起。如果你没有连到网上的话,练习

的时候你可以抛开网络,只让LINUX和自己说话。(但是你的LINUX安装需要配置网络) 

    Client/Server计算的一种通用模式是使用BSD Sockets。BSD就是伯克利软件分发

,UNIX的一个早期版本。理论上讲BSD Socket是一种IP地址和端口号的组合。IP地址定

义了计算机,端口号定义了计算机的逻辑通信信道。(在这里端口不是一种物理设备。

一个物理设备,如以太网卡,可以访问一台计算机的所有端口。) 

    Ivan Griffin和John Nelson在1998年的2月、3月和4月为Linux日志提供了优秀的

三方网络编程的系列文章。2月的文章包含用BSD建立一个基础Client/Server组的代码

;它包括了所有开始时特别需要的东西,你可以从SSC下载这些代码,然后从这篇文章开

始实践更多的内容。 

    把2333.tgz下载后,用tar -xzvf 2333.tgz命令展开它,把2332l1.txt改名为ser

ver.c,2333l2.txt改为client.c。编辑server.c把第一行开始处无关的字符"@cx:"删掉

,还要把最后一行也删掉或用/*和*/把它注释掉。同样,还须把client.c的最后一行注

释掉。用"gcc -oserver server.c"编译server.c用"gcc -oclient client.c"编译cli

ent.c.server运行在本地计算机上,所以它需要知道端口号码来定义一个socket.clie

nt运行在任意一台计算机上,所以它需要知道目标server和server的端口号,你可以使

用成千的端口号。但不要用那些已经被占用了的。你的etc/services文件列出了大部分

被用掉的端口。我发现1024端口工作得较好。 

我曾说过你不必联到网络上,但是你必须配置你的计算机网络来作测试。事实上,这些

代码不能使用localhost这样的通用名来运行,你必须给出计算机的确切的名字。假定

你已经设好了你的网络,输入: 

server 1024 & 

来启动你的Server,然后输入: 

client hostname 1024 

来运行你的client,hostname是你计算机的名字或ip.如果一切正常,你应该能够类似于

下列文字的输出: 

Connection request from 192.168.1.1

14: Hello, World!

第一行给出了client的ip,第二行是server给client的信息。考虑到大量代码的包围,

那句世界著名的"Hello,World"程序宣言是一个很好的入手处。确认你的Server一直在

运行,直到你用fg命令和^C(ctrl-C)来关闭它。   

一个查询--响应Client/Server程序的例子

现在让我们做些更有用的事吧。同时调试两个程序是很无聊的,所以让我们先来点简单

的,模拟Client/Server对的单一程序。当你明白了其中的奥秘之后,我们再把代码分

成Client和Server两部分。在下列的程序中,client用一个叫client的函数来模拟,主

程序模拟Server: /* local test of client-server code */

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

char name[256] = "";

char buffer[256] = "";

void client(char *buffer)

{

 printf("%s", buffer);

 fgets(buffer, 256, stdin);

}

 int main(int argc, char *argv[])

{

 int year, age;

 sprintf(buffer, "Please enter your name: ");

 client(buffer);

 strcpy(name, buffer);

 sprintf(buffer, "Hi, %sPlease enter your year of birth: ", name);

 client(buffer);

 year = atoi(buffer);

 age = 1998 - year;

 sprintf(buffer, "Your approximate age is %d.\nEnter q to quit: ", age);

 client(buffer);

 return(0);

}

    你无须成为一个C语言专家来看懂以上代码,模拟的Server(main)通过数组缓冲送

出一条字符串“please enter you name”给模拟的client(client),client输出字符

串,同时从键盘读入"name",然后通过缓冲区返回。然后server问出生年,当client把

输入的字符串收集来后,server 把它换成数字并和1998相减,并把年龄作为结果返回

给client.一切都做完了,但client需要一个键盘输入来控制退出,server把"q"作为退

出的命令,更老练的写法可以把这个都给省了。这个模拟的client/server演示了在客

户和服务器间传递字符串。提出和回答问题,并进行计算。   

    把上面的码保存为localtest.c。用"gcc -olocaltest localtest.c来编译它,当

你运行它时可以看到下面的输出: Please enter your name: joe

Hi, joe

Please enter your year of birth: 1960

Your approximate age is 38.

Enter q to quit: q

现在让我们把它变成一个真的client/server对。把以下申明插入到server.c的开头部

分: int main(int argc, char *argv[])

{

int i, year, age;

char name[256] = "";

char buffer[256] = "";

char null_buffer[256] = "";

    int serverSocket = 0,

把server.c后部的程序特征代码用如下的代码替代: 

/*

* Server application specific code goes here,(这是Server应用程序特征代码)

* e.g. perform some action, respond to client etc.(执行一些工作,响应client

)*/

sprintf(buffer, "Please enter your name: ");

write(slaveSocket, buffer, strlen(buffer));

for (i = 0; i <= 255; i++) buffer[i] = 0;

/* get name (取得姓名)*/

read(slaveSocket, buffer, sizeof(buffer));

strcpy(name, buffer);

sprintf(buffer, "Hi, %sPlease enter your year of birth: ", name);

write(slaveSocket, buffer, strlen(buffer));

for (i = 0; i <= 255; i++) buffer[i] = 0;

/* get year of birth (取得出生年代)*/

read(slaveSocket, buffer, sizeof(buffer));

year = atoi(buffer);

age = 1998 - year;

sprintf(buffer, "Your approximate age is %d.\nEnter q to quit: ", age);

write(slaveSocket, buffer, strlen(buffer));

close(slaveSocket);

exit(0);

这些代码几乎和模拟的client/server中的是一样的,只不过我们用读写slaveSocket来

替代调用程序。你可以把slaveSocket看作客户和服务器通过socket来连接。 客户的代

码很简单。把下列申明插入到client.c的main函数的申明部分: 

int main(int argc, char *argv[])

{

  int i;

  int clientSocket,

把client.c后部的程序特征代码用如下的代码替代: 

/*

* Client application specific code goes here

* e.g. receive messages from server, respond, etc.

* Receive and respond until server stops sending messages

*/

while (0 < (status = read(clientSocket, buffer, sizeof(buffer))))

  {

    printf("%s", buffer);

    for (i = 0; i <= 255; i++) buffer[i] = 0;

    fgets(buffer, 256, stdin);

    write(clientSocket, buffer, strlen(buffer));

  }

    close(clientSocket);

    return 0;

  }

    同样,这些代码几乎和模拟的client/server中的是一样的。主要的区别是对clie

ntSocket的使用,另一端是server中的slaveSocket,和用来控制程序的while循环。se

rver停止传送信息时while循环就会关闭client. 像刚才一样重新编译server.c和clie

nt.c,并运行它们。这次的输出应该是这样的:   

Connection request from 192.168.1.1

Please enter your name: joe

Hi, joe.

Please enter your year of birth: 1960

Your approximate age is 38.

Enter q to quit: q

现在你可以来真的了:试试用多个client来呼叫同一个server。server会用为每一个cl

ient会话启动一个进程的方法来处理并发的多个请求。这项工作由server.c的fork调用

来完成。读读fork的man帮助可以学到更多东西。   

Client/Server方式的chat程序

   下面是最后一个例子,一个在用户间传送信息的chat程序。这是一个早期的程序,

它只允许每个用户轮流使用,同时它还要求server保持开放一个端口。但它说明了一个

client/server对怎样运行无限制的对话,它也可以被改编成实用的程序。    把以下

申明插入到server.c的开头部分  int main(int argc, char *argv[])

{

  char buffer[256] = "";

  int i, serverquit = 1, clientquit = 1;

    int serverSocket = 0,

把server.c后部的程序特征代码用如下的代码替代: 

/*

* Server application specific code goes here,

* e.g. perform some action, respond to client etc.

*/

printf("Send q to quit.\n");

sprintf(buffer, "Hi, %s\nS: Please start chat. Send q to quit.\n", inet_nto

a(clientName.sin_addr));write(slaveSocket, buffer, strlen(buffer));

for (i = 0; i <= 255; i++) buffer[i] = 0;

while (serverquit != 0 && clientquit != 0)

{

 status = 0;

 while (status == 0)

  status = read(slaveSocket, buffer, sizeof(buffer));

 clientquit = strcmp(buffer, "q\n");

 if (clientquit != 0)

 {

  printf("C: %s", buffer);

  for (i = 0; i <= 255; i++) buffer[i] = 0;

  printf("S: ");

  fgets(buffer, 256, stdin);

  serverquit  = strcmp(buffer, "q\n");

  write(slaveSocket, buffer, strlen(buffer));

  for (i = 0; i <= 255; i++) buffer[i] = 0;

 }

}

printf("Goodbye\n");

close(slaveSocket);

exit(0);

把下列申明插入到client.c的main函数的申明部分。 

int main(int argc, char *argv[])

{

 int i, serverquit = 1, clientquit = 1;

    int clientSocket,

把client.c后部的程序特征代码用如下的代码替代: 

/*

* Client application specific code goes here

* e.g. receive messages from server, respond, etc.

*/

while (serverquit != 0 && clientquit != 0)

{

  status = 0;

  while (status == 0)

    status = read(clientSocket, buffer, sizeof(buffer));

  serverquit = strcmp(buffer, "q\n");

  if (serverquit != 0)

  {

    printf("S: %s", buffer);

    for (i = 0; i <= 255; i++) buffer[i] = 0;

    printf("C: ");

    fgets(buffer, 256, stdin);

    clientquit = strcmp(buffer, "q\n");

    write(clientSocket, buffer, strlen(buffer));

    for (i = 0; i <= 255; i++) buffer[i] = 0;

   }

 }

 printf("Goodbye\n");

 close(clientSocket);

 return 0;

 }

重编译server.c和client.c。为了模拟两台计算机,打开两个X的窗口或使用两个不同

的终端。(alt-1和alt-2)用 server 1024 

在一个窗口中运行server,用 

client hostname 1024 

在另一个窗口中运行client,hostname用你实际的hostname或IP address来替代。ser

ver和client的代码和前面的例子都非常相似。只有两点主要的区别。首先是检测双方

谁输入了"q"来退出程序。serverquit和clientquit用来作为标志。第二是等待另一方

的回应的循环。read函数返回从socket读来的字符的数量;这些存储到status中。一个

非零的字符数表示另一方有消息送到。 

下面是server打印的一个例子: 

Connection request from 192.168.1.1

Send q to quit.

C: Hi server

S: Hi client

C: Bye server

S: Bye client

Goodbye

下面是client打印的一个例子: 

S: Hi, 192.168.1.1

S: Please start chat. Send q to quit.

C: Hi server

S: Hi client

C: Bye server

S: Bye client

C: q

Goodbye

我希望这些例子显示了建立一个client/server计算有多简单。也许你试试自己的应用

的胃口被掉起来了。如果你作出了什么可口的东西,不要忘了让我们都知道,还有就是

一定要保持语句简洁。 

---------------------------------------------------------------------------

-----

版权所有 (C) 1998, John Kacur 

出版于第33期《Linux公报》1998年10月 中文版第一期

---------------------------------------------------------------------------

-----

---------------------------------------------------------------------------

-----

    

---------------------------------------------------------------------------

-----


--
☆ 来源:.哈工大紫丁香 bbs.hit.edu.cn.[FROM: bin@mtlab.hit.edu.cn]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:206.955毫秒