任务要求:目前,这个 Web 服务器一次只处理一个 HTTP 请求。请实现一个能同时处理多个 请求的多线程服务器。首先创建一个主线程,在固定端口监听客户端请求。当从客户端 收到 TCP 连接请求时,它将通过另一个端口建立 TCP 连接,并在另外的单独线程中为 客户端请求提供服务。这样在每个请求/响应对的独立线程中将有一个独立的 TCP 连接。
服务器代码实现:
from socket import *
import sys
import threading
def Server(connectionSocket, addr):
print('Waiting: ', addr)
try:
# Receives the request message from the client
message = connectionSocket.recv(1024).decode()
# Extract the path of the requested object from the message
# The path is the second part of HTTP header, identified by [1]
filename = message.split()[1]
# Because the extracted path of the HTTP request includes
# a character '/', we read the path from the second character
f = open(filename[1:])
# Store the entire content of the requested file in a temporary buffer
outputdata = f.read()
f.close()
# Send the HTTP response header line to the connection socket
header = 'HTTP/1.1 200 OK\r\nConnection: close\r\nContent-type: text/html\r\nContent-Length: %d\r\n\r\n' % (
len(outputdata))
connectionSocket.send(header.encode())
# Send the content of the requested file to the connection socket
for i in range(0, len(outputdata)):
connectionSocket.send(outputdata[i].encode())
# Close the client connection socket
connectionSocket.close()
except IOError:
# Send HTTP response message for file not found
outputdata = 'HTTP/1.1 404 Not Found\r\n\r\n'
print(outputdata)
connectionSocket.send(outputdata.encode())
# Close the client connection socket
connectionSocket.close()
serverSocket = socket(AF_INET, SOCK_STREAM)
serverport = 12000
serverSocket.bind(('', serverport))
serverSocket.listen(5)
print('Please wait for connection')
while True:
connectionSocket, addr = serverSocket.accept()
thread = threading.Thread(target=Server, args=(connectionSocket, addr))
thread.start()
serverSockect.close()
客户端的代码,我愚蠢地列出了五个线程:
from socket import *
import threading
def client_thread(filename='AfterThen.html', i=1):
clientSocket = socket(AF_INET, SOCK_STREAM)
servername = '127.0.0.1'
serverport = 12000
clientSocket.connect((servername, serverport))
message = '''GET /%s HTTP/1.1\r\nHost: %s:%d\r\nConnection: close\r\nUser-Agent: Mozilla/5.0\r\n\r\n''' % (
filename, servername, serverport)
clientSocket.send(message.encode())
data = 1
samplename = 'sample%d.txt' % i
with open(samplename, 'w') as f:
while data:
data = clientSocket.recv(1024)
f.write(data.decode())
f.close()
clientSocket.close()
print('\r\nClient %d has received the message!\r\n' % i)
thread_client_one = threading.Thread(target=client_thread, args=('AfterThen.html', 1))
thread_client_two = threading.Thread(target=client_thread, args=('AfterThen.html', 2))
thread_client_three = threading.Thread(target=client_thread, args=('nothing.html', 3))
thread_client_four = threading.Thread(target=client_thread, args=('AfterThen.html', 4))
thread_client_five = threading.Thread(target=client_thread, args=('nothing.html', 5))
thread_client_one.start()
thread_client_two.start()
thread_client_three.start()
thread_client_four.start()
thread_client_five.start()
文件的html为AfterThen.html,nothing.html是不存在的。
任务结果记录:
1.python版本:3.9
2.验证多线程正确运行的验证方案
编写客户端代码,其中采用多线程方式。在客户端代码中,我设置了5个线程。每个客户线程client_thread在接收完服务器报文后都将报文写入相应的sample.txt(如编号为1的client_thread,将报文写入sample1.txt。其中编号不是线程名字,是我按照程序书写顺序给予线程的编号。),并在客户端运行窗口上打印出“Client相应编号has received the message!”
如果多线程服务器正确运行,服务器运行窗口会打印出不同客户线程与服务器建立连接的IP地址及端口号。客户端运行窗口会打印出5条消息,同时在文件夹中会生成5个sample相应编号.txt文件,打开文件,报文内容与任务4的客户端截图类似,如图1与图2。
图 1 任务4的客户端截图-文件存在
图 2 任务4的客户端截图-文件不存在
3.结果截图
(1)服务器运行窗口截图
(2)客户端运行窗口截图
(3)5个sample相应编号.txt文件截图
(4)sample1.txt截图
(5)sample2.txt截图
(6)sample3.txt截图
(7)sample4.txt截图
(8)sample5.txt截图