python socket编程实验: 简单Web服务器

这是我的数据通信课程作业。基础代码的主要框架已经在实验要求中给出,但是我仍然做了一些结构上的改变。
这个实验的目的是实现一个简单的Web服务器,服务端运行后,在浏览器访问localhost:12345/welcome.html可以得到编写好的HTML页面

要点

  • socket服务端api调用过程: socket->bind->listen->accept
  • 浏览器的GET请求本质上与传字符串无异,借助这个原理可以提取文件名
  • 在发送正文之前发送HTTP头部,用以通知客户端(浏览器)数据内容
  • 在设计时没有考虑客户端(浏览器)如何知道包已经发完,所以在服务端发完所有包之后应该主动断开连接,以免堵塞

基础代码

from socket import *
import sys
import random

serverSocket = socket(AF_INET, SOCK_STREAM)
host = '0.0.0.0'
port = 12345
serverSocket.bind((host, port))  # 绑定地址
serverSocket.listen(5)  # 开始监听

while True:
    # Establish the connection
    print('Ready to serve...')
    connectionSocket, addr = serverSocket.accept()
    try:
        message = connectionSocket.recv(1024)  # 读取消息(请求)
        print(message)
        filename = message.split()[1]  # 获取文件名
        f = open(filename[1:])  # 过滤斜杠
        outputdata = f.read()   # 读取内容
        print(outputdata)
        # 发送HTTP请求头
        connectionSocket.send("HTTP/1.1 201 OK\r\n\r\n".encode('utf-8'))
        for i in range(0, len(outputdata)):
            connectionSocket.send(outputdata[i].encode('utf-8'))
        connectionSocket.send("\r\n".encode('utf-8'))
    except IOError:
        f = open("404.html")
        outputdata = f.read()
        connectionSocket.send("HTTP/1.1 201 OK\r\n\r\n".encode('utf-8'))
        connectionSocket.send(outputdata.encode('utf-8'))
        connectionSocket.send("\r\n".encode('utf-8'))
    except IndexError:
        connectionSocket.send("请求的资源不存在\r\n\r\n".encode('utf-8'))
    finally:
        connectionSocket.close()

serverSocket.close()
sys.exit()

在同级目录下创建welcome.html



    
        
        TCP编程实验1
    
    
        

数据通信课程作业

  • 实验一: 网络服务器
  • 沈同学
  • 通信工程专业

运行结果

运行服务,在浏览器访问localhost:12345/welcome.html
python socket编程实验: 简单Web服务器_第1张图片
可以得到返回的welcome.html网页的内容
如果访问localhost:12345/xxx, 则会得到设定好的404页面

python socket编程实验: 简单Web服务器_第2张图片

程序改进

1. 多线程处理多个请求

  • 核心代码:
# 建立列表保存客户端连接socket
connection_pool = [None] * 50
index = 0
# 将基础代码中的处理消息的部分封装成函数
# 并添加线程启动/结束的信息
def recvClient(connectionSocket):
	print(threading.current_thread().getName() + ' 线程启动')
	# ... ...
	# ... ... 与基础部分几乎相同
	print(threading.current_thread().getName() + ' 线程结束')
# 程序主体
serverSocket = socket(AF_INET, SOCK_STREAM)
host = '0.0.0.0'
port = 12345
serverSocket.bind((host, port))  # 绑定地址
serverSocket.listen(50)  # 开始监听
print('多线程网络服务器开始监听...')
while index < 50:
    connection_pool[index], addr = serverSocket.accept()
    index += 1
    # 创建新的线程
    t = threading.Thread(target=recvClient, args=(connection_pool[index-1], ))
    t.start()
    print('主线程继续监听...')
  • 运行结果
    python socket编程实验: 简单Web服务器_第3张图片
  • 分析:
    有时候访问页面会创建两次线程,原因是浏览器会发送额外的图标请求GET /favicon.ico HTTP/1.1
    该服务器最多可以接收50次请求,且可以修改参数进行扩容

2. 自己编写客户端

  • 代码
from socket import *
import sys
import time

if len(sys.argv) < 3:
    print('参数不足')
    sys.exit()

address = sys.argv[1]  # 通过sys的argv函数获取参数
port = int(sys.argv[2])
filename = sys.argv[3]
clientSocket = socket(AF_INET, SOCK_STREAM)
clientSocket.connect((address, port))

message = 'GET /' + filename  # 使用GET方法

clientSocket.send(message.encode('utf-8'))  # 发送请求
page = ''
while True:
    recv = clientSocket.recv(1024).decode('utf-8')
    page += recv
    if not recv:
        clientSocket.close()      # 当没有消息时关闭连接
        break  

print(page) 
  • 运行结果

访问存在的资源:
python socket编程实验: 简单Web服务器_第4张图片

访问不存在的资源:
python socket编程实验: 简单Web服务器_第5张图片

你可能感兴趣的:(网络技术)