%# -*- coding: utf-8-unix -*-

\section{TCP通信与Web服务器}
\label{sec:c:socket:s:web}

\subsection{实验目的}
\label{subsec:c:socket:s:web_object}

掌握Python中TCP套接字编程的基础知识，理解HTTP报文格式，
了解开发一个简单Web服务器的流程。

\subsection{实验内容}
\label{subsec:c:socket:s:web_content}

使用Python开发一个一次处理一个HTTP请求的Web服务器。
Web服务器接受并解析HTTP请求，从服务器的文件系统中获取请求的文件，
创建一个HTTP响应消息，该消息由前面带有首部行信息的请求文件组成，
然后将响应直接发送给客户端。如果服务器中不存在请求的文件，
则服务器将发送HTTP“404 not Found”的消息给客户端。

\subsection{实验原理、方法和手段}
\label{subsec:c:socket:s:web_principle}

基于TCP协议的面向客户/服务器的工作流程是：
在服务器端首先启动服务器调用socket( )创建套接字；
然后调用bind( )指定服务器socket地址（IP地址+端口号）；
再调用listen( )让服务器做好侦听准备，并规定好请求队列的长度，
然后服务器进入阻塞状态，等待客户的连接请求；
最后通过accept( )来接收连接请求，并获得客户的socket地址。
在客户端，客户调用socket( )创建套接字，然后调用connect( )和服务器建立连接。
连接建立成功后，客户和服务器之间就可以通过调用read( )和write( )来接收和发送数据。
一旦数据传输结束，服务器和客户通过调用close( )来关闭套接字。
具体流程图\ref{fig:c:socket_tcp-flow}所示。

\begin{figure}[!htp]
  \centering
  \includegraphics[width=6cm]{tcp-flow}
  \caption{面向连接客户/服务器流程图}
  \label{fig:c:socket_tcp-flow}
\end{figure}

\subsection{实验条件}
\label{subsec:c:socket:s:web_requirement}

\begin{itemize}
  \item 装有python环境的电脑两台；
  \item 局域网环境；
  \item 部分代码（实验步骤中已给出）。
\end{itemize}

参考资料：

\begin{itemize}
  \item {J.F Kurose and K.W. Ross, 计算机网络自顶向下方法（第7版）}
\end{itemize}

\subsection{实验步骤}
\label{subsec:c:socket:s:web_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:c:socket:s:web_rethink}

本实验中的Web服务器一次只能处理一个HTTP请求，请自行查阅线程知识，
修改代码，实现一个能够同时处理多个请求的多线程服务器。

\subsection{注意事项及有关说明}
\label{subsec:c:socket:s:web_notice}

将HTML文件放在服务器代码同一目录中。运行服务器程序。
确定运行服务器的主机的IP地址（例如，128.238.251.26）。
从另一个主机打开浏览器并提供相应的URL。

例如：\url{http://128.238.251.26:6789/HelloWorld.html}。

“HelloWorld.html”是放置在服务器目录中的文件的名称。
6789为端口号，如果省略则使用默认端口号80。

\subsection{考核方法}
\label{subsec:c:socket:s:web_criterion}

同实验\ref{sec:c:socket:s:udp}。
