服务器软件设计概述
最简单服务器的算法
- 创建套接字
- 绑定到一个熟知端口
- 期望在这个端口上接受请求
- 进入无线循环,接收客户请求并应答
循环与并发
- 循环服务器:一个时刻只处理一个请求
- 并发服务器:一个时刻可以处理多请求
- 多数只提供表面并发:执行多个线程,每个线程处理一个请求
- 使用线程的可能性:计算量小,主要是异步I/O,便于同时使用多个通信信道
- 并发处理多个请求,而不是指下层使用了多个并发线程
- 难以构建,性能好
面向连接和无连接的访问
- TCP/IP提供了两种协议
- 使用TCP的服务器是面向连接的服务器
- 点到点通信
- 建立可靠连接
- 可靠交付
- 具有流控的传输
- 双工传输
- 流模式
- 使用UDP的服务器是无连接的服务器
- 选择面向连接或者无连接的服务依赖于应用协议
面向连接
- 易于编程
- 自动处理分组丢失,分组失序
- 自动验证数据差错,处理连接状态
- 对每个连接都有一个单独的套接字,耗费更多资源
- 在空闲的连接上不发送任何分组
- 始终运行的服务器会因为客户的崩溃,导致无用套接字的过多而耗尽资源
无连接
- 没有资源耗尽问题
- 需要自己完成可靠通信问题
- 必要时,需要一种自适应重传的复杂技术
- 对于可靠通信场合,尽量使用TCP
- 是否需要组播或者广播是考虑何种传输方式的因素
四种基本类型服务器
循环服务器算法
- 循环服务器设计、编程、排错、修改很容易,往往使用无连接的协议
- 循环服务器对于小的处理时间的服务工作很好
- TCP面向连接的循环服务器算法
- 创建套接字并将其绑定到它所提供服务的熟知端口上
- getservbyname:服务器名映射到熟知端口上
- bind:为某个套接字指明端点,使用结构sockaddr_in,该结构包含有IP地址和端口号
- 对于多接口主机使用INADDR_ANY指明一个通配地址,让该主机的任何一个IP地址都能匹配
- 将该端口设置为被动模式,使其准备为服务器所用
- 调用listen将套接字置于被动模式
- 接收并使用连接
- 调用accept获得下一个传入连接请求
- 从该套接字上接收下一个连接请求,获得该连接的新的套接字
- 重复地读取来自客户的请求,构造响应,按照应用协议向客户发回响应
- 当某个特定客户完成交互时,关闭连接,并返回步骤三以接收新的连接
- 无连接循环服务器
- 创建套接字并将其绑定到所提供服务的熟知端口上
- 重复读取来自客户的请求,构造响应,按照应用协议向客户发回响应
- sendto:指明发送的数据报和它将去的地址
- 服务器从收到的请求中的源地址获得应答地址。调用recvfrom得到数据和对方的地址
并发服务器
- 给多个用户提供快速响应时间需要使用并发服务器
- 尽管可以使用一个单线程实现并发服务器,但是大多数使用多线程
- 并发无连接服务器算法
- 主:创建套接字并将其绑定到提供服务的熟知地址上,让该套接字保持未连接
- 主:反复调用recvfrom接收来自客户的下一个请求,创建一个新的从线进程来处理响应
- 从:从来自主进程的特定请求以及到该套接字的访问开始
- 从:根据应用协议构造应答,并用sendto将该应答发回给客户
- 从:退出
- 面向连接的服务器在多个连接之间实现并发
- 主:创建套接字并将其绑定到所提供服务的熟知端口上,让该套接字保持为面向连接
- 主:将该端口设置为被动模式
- 主:反复调用accept以便接收来自客户的下一个连接请求,并创建新的从线程或者进程来处理响应
- 从:由主线程传递来的连接请求开始
- 从:用该连接与客户进行交互,读取请求并发回响应
- 关闭连接并退出