文章目录
计网实验A3:简单的web服务器
实验介绍
首先学习面向TCP连接的套接字编程基础知识:如何创建套接字,将其绑定到特定的地址和端口,以及发送和接收数据包。其次还将学习 HTTP 协议格式的相关知识。在此基础上,本实验开发一个简单的 Web 服务器,它仅能处理一个HTTP连接请求。
相关背景介绍
Socket编程接口
要实现 Web 服务器,需使用套接字 Socket编程接口来使用操作系统提供的网络通信功能。 Socket 是应用层与 TCP/IP 协议族通信的中间软件抽象层,是一组编程接口。它把复杂的 TCP/IP 协议族隐藏在 Socket 接口后面,对用户来说,一组简单的接口就是全部,让 Socket 去组织数据,以符合指定的协议。使用 Socket 后,无需深入理解 TCP/UDP 协议细节(因为Socket 已经为我们封装好了),只需要遵循 Socket 的规定去编程,写出的程序自然就是遵循 TCP/UDP 标准的。Socket 的地位如下图所示:
从某种意义上说,Socket 由地址IP和端口Port构成。IP 是用来标识互联网中的一台主机的位置,而 Port 是用来标识这台机器上的一个应用程序,IP 地址是配置到网卡上的,而 Port 是应用程序开启的,IP 与 Port 的绑定就标识了互联网中独一无二的一个应用程序。
套接字类型 流式套接字(SOCK_STREAM):用于提供面向连接、可靠的数据传输服务。 数据报套接字(SOCK_DGRAM):提供了一种无连接的服务。该服务并不能保证数据传输的可靠性,数据有可能在传输过程中丢失或出现数据重复,且无法保证顺序地接收到数据。 原始套接字(SOCK_RAW):主要用于实现自定义协议或底层网络协议。
在本 WEB 服务器程序实验中,采用流式套接字进行通信。其基本模型如下图所示:
其工作过程如下:服务器首先启动,通过调用 socket() 建立一个套接字,然后调用绑定方法 bind() 将该套接字和本地网络地址联系在一起,再调用 listen() 使套接字做好侦听连接的准备,并设定的连接队列的长度。客户端在建立套接字后,就可调用连接方法 connect() 向服务器端提出连接请求。服务器端在监听到连接请求后,建立和该客户端的连接,并放入连接队列中,并通过调用 accept() 来返回该连接,以便后面通信使用。客户端和服务器连接一旦建立,就可以通过调用接收方法 recv()/recvfrom() 和发送 方法send()/sendto() 来发送和接收数据。最后,待数据传送结束后,双方调用 close() 关闭套接字。
HTTP传输协议
超文本传输协议(HTTP)是用于Web上进行通信的协议:它定义Web浏览器如何从Web服务器请求资源以及服务器如何响应。为简单起见,在该实验中将处理HTTP协议的1.0版。HTTP通信以事务形式进行,其中事务由客户端向服务器发送请求,然后读取响应组成。 请求和响应消息共享一个通用的基本格式:
- 初始行(请求或响应行)
- 零个或多个头部行
- 空行(CRLF)
- 可选消息正文。
对于大多数常见的HTTP事务,协议归结为一系列相对简单的步骤:
首先,客户端创建到服务器的连接;然后客户端通过向服务器发送一行文本来发出请求。这请求行包HTTP方法(比如GET,POST、PUT等),请求URI(类似于URL),以及客户机希望使用的协议版本(比如HTTP/1.0);接着,服务器发送响应消息,其初始行由状态线(指示请求是否成功),响应状态码(指示请求是否成功完成的数值),以及推理短语(一种提供状态代码描述的英文消息组成);最后一旦服务器将响应返回给客户端,它就会关闭连接。
实验功能要求
Web 服务器的基本功能是接受并解析客户端的 HTTP 请求,然后从服务器的文件系统获取所请求的文件,生成一个由头部和响应文件内容所构成成的 HTTP 响应消息,并将该响应消息发送给客户端。如果请求的文件不存在于服务器中,则服务器应该向客户端发送“404 Not Found”差错报文。 具体的过程和步骤分为:
- 当一个客户(浏览器)连接时,创建一个连接套接字;
- 从这个连接套接字接收 HTTP 请求;
- 解释该请求以确定所请求的特定文件;
- 从服务器的文件系统获得请求的文件;
- 创建一个由请求的文件组成的 HTTP 响应报文,报文前面有首部行;
- 经 TCP 连接向请求浏览器发送响应;
- 如果浏览器请求一个在该服务器中不存在的文件,服务器应当返回一个“404 Not Found”差错报文。
总体设计
首先开启服务器,并等待连接请求;浏览器请求访问服务器及其文件,服务器检查请求报文是否包含了关闭指令,若是,则程序停止运行;若否,则检查服务器内是否包含该文件;如果包含,则将请求文件放入输出流返回给浏览器,否则返回“404 NOT FOUND”。
详细设计
数据结构设计
这里不做复杂的数据结构处理,主要分为两个类对象:HttpServer 以及WebServer。WebServer主要是做的监听的内容,HttpServer做的是处理结果,返回目标的内容。
HttpServer继承自线程类,会生成一个线程,独立于主线程进行处理,可以实现一定的并发的能力。
函数分析
监听,并且建立线程处理,这里我们的HttpServer就是进行处理的线程,我们的主进程一直监听内容,但监听到事件时候,生产子线程,进行内容的处理。
public void startServer(int port){
try {
@SuppressWarnings("resource")
ServerSocket serverSocket = new ServerSocket(port); // 绑定端口
while(true){
//服务器套接字
Socket socket = serverSocket.accept();
// serverSocket.accept():服务器接受客户端的连接请求,并返回一个套接字,客户机通过此套接字与服务器通信。
// 如果未连接到客户端,线程处于阻塞状态,程序无法执行下去。
new HttpServer(socket).start(); {
// 先新建一个HttpServer的对象,然后此对象调用HttpServer类的start()方法,把套接字放进去当作参数
};
}
} catch (IOException e) {
e.printStackTrace(); // 出现异常的应对措施
}
}
我们对于请求的处理,会生成一个线程来进行处理,在这个新的线程中,我们通过套接字,获取其中的输入输出流对象,然后进行数据的传输。
// 多线程方法调用
@Override
public void run() {

本文介绍了如何使用Socket编程接口实现一个简单的Web服务器,涉及TCP连接、HTTP协议的基本知识。实验要求服务器接收HTTP请求,解析文件路径,返回文件内容或404NotFound错误。通过监听、接受连接、处理请求和响应,服务器实现了基本的Web服务功能。实验中,服务器处理了请求解析、文件读取和HTTP响应构造。
最低0.47元/天 解锁文章
1531





