Good in study, attitude and health

计算机网络-使用Socket完成一个简易Web服务器

实验内容


在本实验中,您将学习 Python 中 TCP 连接的套接字编程的基础知识:如何创建套接字,将其绑定到特定的地址和端口,以及发送和接收 HTTP 数据包。您还将学习一些 HTTP 首部格式的基础知识。 您将开发一个处理一个 HTTP 请求的 Web 服务器。您的 Web 服务器应该接受并解析 HTTP 请求,然后从服务器的文件系统获取所请求的文件,创建一个由响应文件组成的 HTTP 响应消息,前面是首部行,然后将响应直接发送给客户端。如果请求的文件不存在于服务器中,则服务器应该向客户端发送“404 Not Found”差错报文。

代码


在文件下面你会找到 Web 服务器的代码框架。您需要填写这个代码。而且需要在标有# Fill in start# Fill in end的地方填写代码。另外,每个地方都可能需要不止一行代码。

运行服务器


将 HTML 文件(例如 HelloWorld.html)放在服务器所在的目录中。运行服务器程序。确认运行服务器的主机的 IP 地址(例如 128.238.251.26)。从另一个主机,打开浏览器并提供相应的 URL。例如: http://128.238.251.26:6789/HelloWorld.html

“HelloWorld.html”是您放在服务器目录中的文件。还要注意使用冒号后的端口号。您需要使用服务器代码中使用的端口号来替换此端口号。在上面的例子中,我们使用了端口号 6789. 浏览器应该显示 HelloWorld.html 的内容。如果省略“:6789”,浏览器将使用默认端口 80,只有当您的服务器正在端口 80 监听时,才会从服务器获取网页。

然后用客户端尝试获取服务器上不存在的文件。你应该会得到一个“404 Not Found”消息。

代码模版


# import socket module
from socket import *
serverSocket = socket(AF_INET, SOCK_STREAM)
# Prepare a sever socket
# Fill in start
# Fill in end
while True:
    # Establish the connection
    print 'Ready to serve...'
    connectionSocket, addr =   # Fill in start  # Fill in end
    try:
        message =   # Fill in start  # Fill in end
        filename = message.split()[1]
        f = open(filename[1:])
        outputdata = # Fill in start  # Fill in end
        # Send one HTTP header line into socket
        # Fill in start
        # Fill in end

        # Send the content of the requested file to the client
        for i in range(0, len(outputdata)):
            connectionSocket.send(outputdata[i])
        connectionSocket.close()
    except IOError:
        # Send response message for file not found
        # Fill in start
        # Fill in end

        # Close client socket
        # Fill in start
        # Fill in end
serverSocket.close()

实现代码


# import socket module
from socket import *
serverSocket = socket(AF_INET, SOCK_STREAM)
# Prepare a sever socket

server_port = 12000
serverSocket.bind(('', server_port))
serverSocket.listen(1)

while True:
    # Establish the connection
    print ('Ready to serve...')
    connectionSocket, addr = serverSocket.accept()
    try:
        message = connectionSocket.recv(1024).decode()
        filename = message.split()[1] # /HelloWorld.html
        # with open(filename[1:], "r") as f: # HelloWorld.html
        #     outputdata = [line.encode() for line in f]
        f = open(filename[1:])
        outputdata = f.read()
        # Send one HTTP header line into socket
        # 最后有一行空行,用来分割响应头和响应体
        # String
        response_headers = (
            "HTTP/1.1 200 OK\r\n"
            "Content-Type: text/html; charset=utf-8\r\n"
            "Connection: close\r\n"
            f"Content-Length: {len(outputdata)}\r\n"
            "\r\n"
        )

        connectionSocket.send(response_headers.encode())

        # Send the content of the requested file to the client
        for i in range(0, len(outputdata)):
            connectionSocket.send(outputdata[i].encode())
        connectionSocket.close()
    except IOError:
        # Send response message for file not found
        error = "HTTP/1.1 404 Not Found\r\n"
        connectionSocket.send(error.encode())

        # Close client socket
        connectionSocket.close()
serverSocket.close()

易错点:响应头的格式以及每行之后都要加上\r\n否则不起作用