📄 48.htm
字号:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>CTerm非常精华下载</title>
</head>
<body bgcolor="#FFFFFF">
<table border="0" width="100%" cellspacing="0" cellpadding="0" height="577">
<tr><td width="32%" rowspan="3" height="123"><img src="DDl_back.jpg" width="300" height="129" alt="DDl_back.jpg"></td><td width="30%" background="DDl_back2.jpg" height="35"><p align="center"><a href="http://apue.dhs.org"><font face="黑体"><big><big>123</big></big></font></a></td></tr>
<tr>
<td width="68%" background="DDl_back2.jpg" height="44"><big><big><font face="黑体"><p align="center"> ● UNIX网络编程 (BM: clown) </font></big></big></td></tr>
<tr>
<td width="68%" height="44" bgcolor="#000000"><font face="黑体"><big><big><p align="center"></big></big><a href="http://cterm.163.net"><img src="banner.gif" width="400" height="60" alt="banner.gif"border="0"></a></font></td>
</tr>
<tr><td width="100%" colspan="2" height="100" align="center" valign="top"><br><p align="center">[<a href="index.htm">回到开始</a>][<a href="19.htm">上一层</a>][<a href="49.htm">下一篇</a>]
<hr><p align="left"><small> <br>
Linux网络编程--9. 服务器模型 <br>
http://linuxc.51.net 作者:hoyt (2001-05-08 11:23:59) <br>
学习过《软件工程》吧.软件工程可是每一个程序员"必修"的课程啊.如果你没有学 <br>
习过, 建议你去看一看. 在这一章里面,我们一起来从软件工程的角度学习网络编程的思 <br>
想.在我们写程序之前, 我们都应该从软件工程的角度规划好我们的软件,这样我们开发 <br>
软件的效率才会高. 在网络程序里面,一般的来说都是许多客户机对应一个服务器.为了 <br>
处理客户机的请求, 对服务端的程序就提出了特殊的要求.我们学习一下目前最常用的服 <br>
务器模型. <br>
循环服务器:循环服务器在同一个时刻只可以响应一个客户端的请求 <br>
并发服务器:并发服务器在同一个时刻可以响应多个客户端的请求 <br>
9.1 循环服务器:UDP服务器 <br>
UDP循环服务器的实现非常简单:UDP服务器每次从套接字上读取一个客户端的请求,处理 <br>
, 然后将结果返回给客户机. <br>
可以用下面的算法来实现. <br>
socket(...); <br>
bind(...); <br>
while(1) <br>
{ <br>
recvfrom(...); <br>
process(...); <br>
sendto(...); <br>
} <br>
} <br>
因为UDP是非面向连接的,没有一个客户端可以老是占住服务端. 只要处理过程不是死循 <br>
环, 服务器对于每一个客户机的请求总是能够满足. <br>
9.2 循环服务器:TCP服务器 <br>
TCP循环服务器的实现也不难:TCP服务器接受一个客户端的连接,然后处理,完成了这个客 <br>
户的所有请求后,断开连接. <br>
算法如下: <br>
socket(...); <br>
bind(...); <br>
listen(...); <br>
while(1) <br>
{ <br>
accept(...); <br>
while(1) <br>
{ <br>
read(...); <br>
process(...); <br>
write(...); <br>
} <br>
close(...); <br>
} <br>
TCP循环服务器一次只能处理一个客户端的请求.只有在这个客户的所有请求都满足后, <br>
服务器才可以继续后面的请求.这样如果有一个客户端占住服务器不放时,其它的客户机 <br>
都不能工作了.因此,TCP服务器一般很少用循环服务器模型的. <br>
9.3 并发服务器:TCP服务器 <br>
为了弥补循环TCP服务器的缺陷,人们又想出了并发服务器的模型. 并发服务器的思想是 <br>
每一个客户机的请求并不由服务器直接处理,而是服务器创建一个 子进程来处理. <br>
算法如下: <br>
socket(...); <br>
bind(...); <br>
listen(...); <br>
while(1) <br>
{ <br>
accept(...); <br>
if(fork(..)==0) <br>
{ <br>
while(1) <br>
{ <br>
read(...); <br>
process(...); <br>
write(...); <br>
} <br>
close(...); <br>
exit(...); <br>
} <br>
} <br>
close(...); <br>
} <br>
TCP并发服务器可以解决TCP循环服务器客户机独占服务器的情况. 不过也同时带来了一 <br>
个不小的问题.为了响应客户机的请求,服务器要创建子进程来处理. 而创建子进程是一 <br>
种非常消耗资源的操作. <br>
9.4 并发服务器:多路复用I/O <br>
为了解决创建子进程带来的系统资源消耗,人们又想出了多路复用I/O模型. <br>
首先介绍一个函数select <br>
int select(int nfds,fd_set *readfds,fd_set *writefds, <br>
fd_set *except fds,struct timeval *timeout) <br>
void FD_SET(int fd,fd_set *fdset) <br>
void FD_CLR(int fd,fd_set *fdset) <br>
void FD_ZERO(fd_set *fdset) <br>
int FD_ISSET(int fd,fd_set *fdset) <br>
一般的来说当我们在向文件读写时,进程有可能在读写出阻塞,直到一定的条件满足. 比 <br>
如我们从一个套接字读数据时,可能缓冲区里面没有数据可读(通信的对方还没有 发送数 <br>
据过来),这个时候我们的读调用就会等待(阻塞)直到有数据可读.如果我们不 希望阻塞 <br>
,我们的一个选择是用select系统调用. 只要我们设置好select的各个参数,那么当文件 <br>
可以读写的时候select回"通知"我们 说可以读写了. readfds所有要读的文件文件描述 <br>
符的集合 <br>
writefds所有要的写文件文件描述符的集合 <br>
exceptfds其他的服要向我们通知的文件描述符 <br>
timeout超时设置. <br>
nfds所有我们监控的文件描述符中最大的那一个加1 <br>
在我们调用select时进程会一直阻塞直到以下的一种情况发生. 1)有文件可以读.2)有文 <br>
件可以写.3)超时所设置的时间到. <br>
为了设置文件描述符我们要使用几个宏. FD_SET将fd加入到fdset <br>
FD_CLR将fd从fdset里面清除 <br>
FD_ZERO从fdset中清除所有的文件描述符 <br>
FD_ISSET判断fd是否在fdset集合中 <br>
使用select的一个例子 <br>
int use_select(int *readfd,int n) <br>
{ <br>
fd_set my_readfd; <br>
int maxfd; <br>
int i; <br>
maxfd=readfd[0]; <br>
for(i=1;i if(readfd[i]>maxfd) maxfd=readfd[i]; <br>
while(1) <br>
{ <br>
/* 将所有的文件描述符加入 */ <br>
FD_ZERO(&my_readfd); <br>
for(i=0;i FD_SET(readfd[i],*my_readfd); <br>
/* 进程阻塞 */ <br>
select(maxfd+1,& my_readfd,NULL,NULL,NULL); <br>
/* 有东西可以读了 */ <br>
for(i=0;i if(FD_ISSET(readfd[i],&my_readfd)) <br>
{ <br>
/* 原来是我可以读了 */ <br>
we_read(readfd[i]); <br>
} <br>
} <br>
} <br>
使用select后我们的服务器程序就变成了. <br>
初始话(socket,bind,listen); <br>
while(1) <br>
{ <br>
设置监听读写文件描述符(FD_*); <br>
调用select; <br>
如果是倾听套接字就绪,说明一个新的连接请求建立 <br>
{ <br>
建立连接(accept); <br>
加入到监听文件描述符中去; <br>
} <br>
否则说明是一个已经连接过的描述符 <br>
{ <br>
进行操作(read或者write); <br>
} <br>
} <br>
多路复用I/O可以解决资源限制的问题.着模型实际上是将UDP循环模型用在了TCP上面. <br>
这也就带来了一些问题.如由于服务器依次处理客户的请求,所以可能会导致有的客户 会 <br>
等待很久. <br>
9.5 并发服务器:UDP服务器 <br>
人们把并发的概念用于UDP就得到了并发UDP服务器模型. 并发UDP服务器模型其实是简单 <br>
的.和并发的TCP服务器模型一样是创建一个子进程来处理的 算法和并发的TCP模型一样 <br>
. <br>
除非服务器在处理客户端的请求所用的时间比较长以外,人们实际上很少用这种模型. <br>
9.6 一个并发TCP服务器实例 <br>
#include <br>
#include <br>
#include <br>
#include <br>
#include <br>
#define MY_PORT 8888 <br>
int main(int argc ,char **argv) <br>
{ <br>
int listen_fd,accept_fd; <br>
struct sockaddr_in client_addr; <br>
int n; <br>
if((listen_fd=socket(AF_INET,SOCK_STREAM,0))<0) <br>
{ <br>
printf("Socket Error:%s\n\a",strerror(errno)); <br>
exit(1); <br>
} <br>
bzero(&client_addr,sizeof(struct sockaddr_in)); <br>
client_addr.sin_family=AF_INET; <br>
client_addr.sin_port=htons(MY_PORT); <br>
client_addr.sin_addr.s_addr=htonl(INADDR_ANY); <br>
n=1; <br>
/* 如果服务器终止后,服务器可以第二次快速启动而不用等待一段时间 */ <br>
setsockopt(listen_fd,SOL_SOCKET,SO_REUSEADDR,&n,sizeof(int)); <br>
if(bind(listen_fd,(struct sockaddr *)&client_addr,sizeof(client_addr))<0) <br>
{ <br>
printf("Bind Error:%s\n\a",strerror(errno)); <br>
exit(1); <br>
} <br>
listen(listen_fd,5); <br>
while(1) <br>
{ <br>
accept_fd=accept(listen_fd,NULL,NULL); <br>
if((accept_fd<0)&&(errno==EINTR)) <br>
continue; <br>
else if(accept_fd<0) <br>
{ <br>
printf("Accept Error:%s\n\a",strerror(errno)); <br>
continue; <br>
} <br>
if((n=fork())==0) <br>
{ <br>
/* 子进程处理客户端的连接 */ <br>
char buffer[1024]; <br>
close(listen_fd); <br>
n=read(accept_fd,buffer,1024); <br>
write(accept_fd,buffer,n); <br>
close(accept_fd); <br>
exit(0); <br>
} <br>
else if(n<0) <br>
printf("Fork Error:%s\n\a",strerror(errno)); <br>
close(accept_fd); <br>
} <br>
} <br>
你可以用我们前面写客户端程序来调试着程序,或者是用来telnet调试 <br>
---------------------------------------------------------------------------- <br>
---- <br>
相关文章 关键词 <br>
Linux网络编程--8. 套接字选项 (2001-05-08 11:23:24) <br>
Linux网络编程--7. TCP/IP协议 (2001-05-08 11:22:40) <br>
Linux网络编程--6. 高级套接字函数 (2001-05-08 11:22:09) <br>
Linux网络编程--5. 用户数据报发送 (2001-05-08 11:21:31) <br>
Linux网络编程--4. 完整的读写函数 (2001-05-08 11:20:52) <br>
Linux网络编程--3. 服务器和客户机的信息函数 (2001-05-08 11:20:14) <br>
Linux网络编程--2. 初等网络函数介绍(TCP) (2001-05-08 11:19:34) <br>
Linux网络编程--1. Linux网络知识介绍 (2001-05-08 11:16:55) <br>
樊强制作 欢迎分享 2001 <br>
<br>
</small><hr>
<p align="center">[<a href="index.htm">回到开始</a>][<a href="19.htm">上一层</a>][<a href="49.htm">下一篇</a>]
<p align="center"><a href="http://cterm.163.net">欢迎访问Cterm主页</a></p>
</table>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -