从之前的程序中也可以总结出来一般面向连接的服务器程序的代码框架,一般的模型如下所示:
int main() { socket(…); bind(…); listen(…); while(1) { accept(…); while(1) { pead(…); process(…); write(…); } close(…); } return 0; }
这种面向连接的服务器有一个很大的弊端:服务器一次只能处理一个客户端的请求,只有在这个客户的所有请求都满足之后,服务器才能继续处理后面的请求。如果有一个客户端占用服务器,后边的客户机都不能工作。这样的模型效率太低,不适合实际使用。一种很好的解决办法就是使用并发服务器的框架,流程图如下:
并发服务器的一般模型模型代码如下:
int main(void) { socket(…); bind(…); listen(…); while(1) { accept(…); if(forhk(…) == 0) { while(1) { close(…); read(…); process(…); write(…); } close(…); exit(…); } else close(…); } close(…); return 0; }
上边的模型中,子进程负责处理连接请求,因此关闭监听套接字;父进程继续监听连接请求,因此关闭连接套接字。当服务器程序退出后,则关闭监听套接字。由此可见,在并发服务器的代码框架中,套接字的创建和关闭也是一一对应的,可以使用这种方法来检查自己的程序是否正确。
对于面向连接的服务器,并发服务器可以解决循环服务器客户机独占服务器的情况,但是也存在一些新的问题:
1、服务器要创建子进程来处理客户端的连接请求,但是创建子进程是一种非常消耗资源的操作。为了提高效率必须使用更好的算法。
2、子进程结束运行后,注意对其资源的回收,否则会造成大量的僵尸进程,这可能会导致系统崩溃。
在使用并发服务器程序的代码框架的时候,需要注意上边这两个问题。