|
|
%# -*- coding: utf-8-unix -*-
|
|
|
|
|
|
\section{TCP通信与Web服务器}
|
|
|
\label{sec:c2_s2}
|
|
|
|
|
|
\subsection{实验目的}
|
|
|
\label{subsec:c2_s2_object}
|
|
|
|
|
|
掌握Python中TCP套接字编程的基础知识,理解HTTP报文格式,
|
|
|
了解开发一个简单Web服务器的流程。
|
|
|
|
|
|
\subsection{实验内容}
|
|
|
\label{subsec:c2_s2_content}
|
|
|
|
|
|
使用Python开发一个一次处理一个HTTP请求的Web服务器。
|
|
|
Web服务器接受并解析HTTP请求,从服务器的文件系统中获取请求的文件,
|
|
|
创建一个HTTP响应消息,该消息由前面带有首部行信息的请求文件组成,
|
|
|
然后将响应直接发送给客户端。如果服务器中不存在请求的文件,
|
|
|
则服务器将发送HTTP“404 not Found”的消息给客户端。
|
|
|
|
|
|
\subsection{实验原理、方法和手段}
|
|
|
\label{subsec:c2_s2_principle}
|
|
|
|
|
|
基于TCP协议的面向客户/服务器的工作流程是:
|
|
|
在服务器端首先启动服务器调用socket( )创建套接字;
|
|
|
然后调用bind( )指定服务器socket地址(IP地址+端口号);
|
|
|
再调用listen( )让服务器做好侦听准备,并规定好请求队列的长度,
|
|
|
然后服务器进入阻塞状态,等待客户的连接请求;
|
|
|
最后通过accept( )来接收连接请求,并获得客户的socket地址。
|
|
|
在客户端,客户调用socket( )创建套接字,然后调用connect( )和服务器建立连接。
|
|
|
连接建立成功后,客户和服务器之间就可以通过调用read( )和write( )来接收和发送数据。
|
|
|
一旦数据传输结束,服务器和客户通过调用close( )来关闭套接字。具体流程图如下图所示。
|
|
|
|
|
|
\begin{figure}[!htp]
|
|
|
\centering
|
|
|
\includegraphics[width=6cm]{c2_tcp-flow}
|
|
|
\caption{面向连接客户/服务器流程图}
|
|
|
\label{fig:c2_udp-flow}
|
|
|
\end{figure}
|
|
|
|
|
|
\subsection{实验条件}
|
|
|
\label{subsec:c2_s2_requirement}
|
|
|
|
|
|
\begin{itemize}
|
|
|
\item 装有python环境的电脑两台;
|
|
|
\item 局域网环境;
|
|
|
\item 部分代码(实验步骤中已给出)。
|
|
|
\end{itemize}
|
|
|
|
|
|
\subsection{实验步骤}
|
|
|
\label{subsec:c2_s2_procedure}
|
|
|
|
|
|
开发一个简单的Web服务器,一次处理一个请求,具体要求如下:
|
|
|
\begin{enumerate}
|
|
|
\item 当收到请求时创建一个连接套接字;
|
|
|
\item 通过这个连接套接字接收HTTP请求;
|
|
|
\item 解释HTTP请求以确定所请求的特定文件;
|
|
|
\item 从服务器的文件系统获得请求的文件;
|
|
|
\item 创建一个由请求的文件组成的HTTP响应报文;
|
|
|
\item 通过TCP连接返回响应。
|
|
|
\end{enumerate}
|
|
|
|
|
|
补充完善下面的的服务器代码,完成要求功能。
|
|
|
运行服务器代码,在不同主机上的使用浏览器发送请求测试服务器,分析并记录结果。
|
|
|
\begin{code}[python]
|
|
|
#import socket module
|
|
|
from socket import *
|
|
|
#准备服务器端socket
|
|
|
serverSocket = socket(AF_INET, SOCK_STREAM)
|
|
|
#按需补充代码
|
|
|
while True:
|
|
|
#建立连接
|
|
|
print 'Ready to serve...'
|
|
|
connectionSocket, addr = #按需补充
|
|
|
try:
|
|
|
message = #按需补充
|
|
|
filename = message.split()[1]
|
|
|
f = open(filename[1:])
|
|
|
#通过socket发送HTTP首部行
|
|
|
outputdata = #按需补充
|
|
|
#将请求文件的内容发送到客户端
|
|
|
for i in range(0, len(outputdata)):
|
|
|
connectionSocket.send(outputdata[i])
|
|
|
connectionSocket.close()
|
|
|
except IOError:
|
|
|
#发送未找到文件的响应消息
|
|
|
#按需补充代码
|
|
|
#关闭客户端socket
|
|
|
#按需补充代码
|
|
|
serverSocket.close()
|
|
|
\end{code}
|
|
|
|
|
|
\subsection{思考题}
|
|
|
\label{subsec:c2_s2_rethink}
|
|
|
|
|
|
本实验中的Web服务器一次只能处理一个HTTP请求,请自行查阅线程知识,
|
|
|
修改代码,实现一个能够同时处理多个请求的多线程服务器。
|
|
|
|
|
|
\subsection{注意事项及有关说明}
|
|
|
\label{subsec:c2_s2_notice}
|
|
|
|
|
|
将HTML文件放在服务器代码同一目录中。运行服务器程序。
|
|
|
确定运行服务器的主机的IP地址(例如,128.238.251.26)。
|
|
|
从另一个主机打开浏览器并提供相应的URL。
|
|
|
|
|
|
例如:\url{http://128.238.251.26:6789/HelloWorld.html}。
|
|
|
|
|
|
“HelloWorld.html”是放置在服务器目录中的文件的名称。
|
|
|
6789为端口号,如果省略则使用默认端口号80。
|
|
|
|
|
|
\subsection{考核方法}
|
|
|
\label{subsec:c2_s2_criterion}
|
|
|
|
|
|
同实验\ref{sec:c2_s1}。
|