SOCKET:服务器设计
1.1 迭代服务器和并发服务器
- 迭代服务器:该服务器每次只能处理一个客户端,只有当完全处理完一个客户端之后,才能处理下一个客户端
- 并发服务器:该类型的服务器可以同时处理多个客服端的请求,传统的并发服务器是在父进程当中,为一个新的客户端请求开辟一个新的进程,当然也可以用新的线程
1.2 迭代型 UDP echo服务器
- echo服务支持UDP和TCP,工作在端口号7上,因为端口7是保留端口必须以超级用户权限运行
1.3并发型TCP echo服务器
- 服务器端:父进程每次接收到客户端连接请求之后,调用一个fork函数,创建一个子进程,然后父进程进入死循环等待下一次客户端请求
- 服务器端:由于子进程会复制父进程的所有文件描述符(包括监听套接字和连接套接字)
- 父进程负责监听,所以创建完子进程之后,要关闭连接套接字,在进入下次监听,否则文件描述符可能会被父进程用完
- 子进程负责处理客户端的请求,所以不需要监听套接字,所以在子进程里面必须要关闭监听套接字,处理完之后,子进程结束
1.4 并发型服务器的其它设计方案
- 在服务器上预先创建进程或线程
- 服务器程序启动阶段就创建一定数量的子进程(线程),而不是针对某一个客户端来创建一个新进程,这些子进程就构成了一个服务池
- 服务池当中的子进程每次处理一个客户端请求,处理完之后,子进程并不会结束,而是等待下一次的客户端请求
- 父进程要动态监视服务池,保证服务池能够满足客户端的请求,保证负载均衡
- 尽量做到一个子进程对应一个客户端,也就是说当客户端请求来之后,只有一个子进程可以调用accept()函数
- 单个进程中处理多个客户端
- 一般采用I/O多路复用的模型,比如epoll或者select等系统调用
- 采用服务器集群
1.5 inetd(internet超级服务器)守护进程
*/etc/services
下罗列了系统的不同服务项目,xinetd
是inetd
的扩展版本
-
守护进程
inetd
设计目的:- 监视一组特定的套接字端口,按照要求启动相应服务,而不需要为每一个服务建立一个守护进程
- inetd简化了启动相关服务的编程工作,服务可能仅仅只需要对客户端的请求做处理就可以了,监听,绑定这些工作可能inetd就已经做完了
-
inetd
启动成为守护进程之后所做的一些操作:- 为每一个在
/etc/inetd.conf
中指定的服务建立一个套接字并且绑定到指定端口,每个TCP套接字还会进行listen()
- 通国select()监视每一个套接字是否有请求或者数据报发送过来
select()
进入阻塞态,直到有请求或者数据报到来,TCP中会先执行accept()
调用,在执行下一步inetd
调用fork()
函数创建一个新的进程,通过exec启动服务器程序,在执行exec()
之前,子进程还会做一下步骤:- 关闭初套接字描述符之外的所有描述符
- 使用文件描述符复制技术,使得文件描述符0、1、2指向和套接字文件描述符指向一样的内容,然后关闭套接字文件描述符
- 第3步中,TCP接受连个连求请求之后,inetd就会关闭连接描述符,因为处理部分是在相应的服务器子进程中处理
inetd
跳转回到第2步
- 为每一个在
-
/etc/inetd.conf
配置文件介绍 -
login:服务名称字段,可以在
/etc/services
中找到该服务以及相关的端口号,结合协议字段就可以在该服务的端口号 -
stream:套接字类型字段
-
tcp:协议字段,该字段可以查看
/etc/protocols
文件 -
nowait:标记字段,也可以是wait
- wait:被执行的服务器进程来执行接受连接,对于大部分udp服务器基本上设置为wait
- nowait:inetd监听并且执行accept函数
- root:登录名字段
- /usr/sbin/tcpd:服务器程序存放路径字段
- in.rlogind:服务器程序参数字段,可以是多个参数,每个参数由空格隔开,每个参数送到程序中从argv[0]开始
- 当配置/etc/inetd.conf文件修改之后,我们需要给inetd进程发送一个信号,让它重新读取配置文件
- 最新版的超级服务器配置文件在哪里?