惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

F
Fortinet All Blogs
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
有赞技术团队
有赞技术团队
www.infosecurity-magazine.com
www.infosecurity-magazine.com
大猫的无限游戏
大猫的无限游戏
爱范儿
爱范儿
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Threatpost
V
Visual Studio Blog
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - Franky
人人都是产品经理
人人都是产品经理
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
The Cloudflare Blog
N
News and Events Feed by Topic
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
酷 壳 – CoolShell
酷 壳 – CoolShell
V
V2EX
AWS News Blog
AWS News Blog
S
SegmentFault 最新的问题
T
Tailwind CSS Blog
Hugging Face - Blog
Hugging Face - Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Spread Privacy
Spread Privacy
J
Java Code Geeks
博客园 - 聂微东
T
Tor Project blog
宝玉的分享
宝玉的分享
博客园 - 叶小钗
Webroot Blog
Webroot Blog
博客园 - 【当耐特】
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
H
Heimdal Security Blog
Y
Y Combinator Blog
T
The Blog of Author Tim Ferriss
MongoDB | Blog
MongoDB | Blog
I
InfoQ
Security Latest
Security Latest
Martin Fowler
Martin Fowler
Hacker News: Ask HN
Hacker News: Ask HN
P
Privacy International News Feed
C
CERT Recently Published Vulnerability Notes
Latest news
Latest news
雷峰网
雷峰网
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
Cisco Blogs
H
Help Net Security
L
LINUX DO - 最新话题
L
LINUX DO - 热门话题

风萧古道 - 勤学苦练,年复一年

游戏服务器开发经验(五)应对复杂需求 沉浸式体验东汉末年生活 - 《真三国无双 起源》玩后感 怒其不争!致2025年HLTV的Top18-NiKo Linux家用服务器维护指南 游戏服务器开发经验(四)避免写Bug的习惯、技巧和心态 游戏服务器开发经验(三)线上维护 游戏服务器开发经验(二)避免内存泄露 游戏服务器开发经验(一)道具防刷 35岁找不到工作,绝对不会是软件开发人员的结局 用爱发电项目开发两个月的心得体会 以魏延“子午谷奇谋”讨论软件需求可行性问题 MQTT协议中可变长度的具体计算方式(有计算过程解析) 关于游戏服务器配置表功能的探讨 Java并发编程中上锁的几种方式 如何用C++分割一个字符串? CSAPP第二章-信息的表示与处理 我的自我介绍 Windows XP虚拟机中文版无需激活下载 Java TreeSet的一些用法和特性 Linux C++ Socket实战 传统软件服务器与游戏服务器架构区别 独立个人项目开发心得 - 任务切分、挑战性、实用性和半途而废 使用Python实现简单UDP Ping Kotlin手动实现一个最简单的哈希表 Kotlin实现二叉堆、大顶堆、优先级队列 搭建Spark实战环境(3台linux虚拟机集群)(一)样板机的搭建 Springboot操作MongoDB,包括增改查及复杂操作 Unison在Linux下的安装与使用 Java实现类似WINSCP访问远程Linux服务器,执行命令、上传文件、下载文件 一个被废弃的项目——自动爬取信息然后发给我自己邮箱上 Python连接MongoDB和Oracle实战 MongoDB常用查询语句 vue和springboot项目部署到Linux服务器 Python的一些用法(可能不定时更新) java正则表达式 - 双反斜杠(\)和Pattern的matches()与find() 简述爬虫对两种网站的不同爬取方式 Vue的路由配置及手动改地址栏为啥又跳转回来?? [JavaScript]JS基础知识 [Mybatis]逆向工程中Select语句查询不出‘TEXT’字段 [编译原理]FIRST、FOLLOW和SELECT [Spring]Spring学习笔记 [算法]分布估计算法 - 一种求解多维背包问题的混合分布估计算法_王凌 [日常]我做独立博客的原因 人间值得 深入理解计算机系统 想想就开心! 最重要的事,只有一件 藏书 被讨厌的勇气 关于 简历 朋友 尊重自己:给予与接收的心灵艺术
使用Python开发一个简单的web服务器
JonathanLin · 2021-11-07 · via 风萧古道 - 勤学苦练,年复一年

来自书籍《计算机网络-自顶向下方法-第6版(课本)》第120页,第二章应用层的课后题第一题。

基础题目

题目:在这个编程作业中,你将用Python语言开发一个简单的Web服务器,它仅能处理一个请求。具体而言,你的Web服务器将:(1)当一个客户(浏览器)联系时创建一个连接套接字;(2)从这个连接接收HTTP请求;(3)解释该请求以确定所请求的特定文件;(4)从服务器的文件系统获得请求的文件;(5)创建一个由请求的文件组成的HTTP响应报文,报文前面有首部行;(6)经TCP连接向请求的浏览器发送响应。如果浏览器请求一个在该服务器中不存在的文件,服务器应当返回一个“404 Not Found”差错报文。

参考或者说学习了github上moranzcw的仓库:Computer-Networking-A-Top-Down-Approach-NOTES的内容,完成了这道题。

代码https://github.com/moranzcw如下:

# import socket module
from socket import *

serverSocket = socket(AF_INET, SOCK_STREAM)
# Prepare a sever socket
# Fill in start
# 定义ip和端口号,然后bind绑定socket
host = ''
port = 6789
serverSocket.bind((host, port))
serverSocket.listen(1)
# Fill in end
while True:
    # Establish the connection
    print('Ready to serve...')
    connectionSocket, addr = serverSocket.accept()
    # Fill in start  #Fill in end
    try:
        message = connectionSocket.recv(1024)  # Fill in start  #Fill in end
        filename = message.split()[1]
        f = open(filename[1:])
        outputdata = f.read()  # Fill in start  #Fill in end
        # Send one HTTP header line into socket
        # Fill in start
        header = ' HTTP/1.1 200 OK\nConnection: close\nContent-Type: text/html\nContent-Length: %d\n\n' % (
            len(outputdata))
        connectionSocket.send(header.encode())

        # Fill in end

        # 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
        # Fill in start
        header = ' HTTP/1.1 404 Found'
        connectionSocket.send(header.encode())
        connectionSocket.close()
        # Fill in end

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

同时在这个文件的同级目录下,有一个html文件:helloWorld.html

<head>Hello world!</head>
<body>abcdefg</body>

在Python中启动项目:

然后打开浏览器,在地址栏内输入:http://localhost:6789/helloWorld.html

可以看到浏览器正常收到HTTP响应报文,显示正常。

如果输入的地址不是helloWorld.html,则会报404。

进阶题目

进阶题目1

题目也是翻译自github老哥之手,感谢。

题目:目前,这个Web服务器一次只处理一个HTTP请求。请实现一个能够同时处理多个请求的多线程服务器。使用线程,首先创建一个主线程,在固定端口监听客户端请求。当从客户端收到TCP连接请求时,它将通过另一个端口建立TCP连接,并在另外的单独线程中为客户端请求提供服务。这样在每个请求/响应对的独立线程中将有一个独立的TCP连接。

不难得知,只要用线程包装一下处理socket的方法即可。

代码如下:

# import socket module
import threading
from socket import *


def sonTcpConnect(connectionSocket):
    # Fill in start  #Fill in end
    try:
        print("thread:  " + threading.currentThread().name + " is working...")
        message = connectionSocket.recv(1024)  # Fill in start  #Fill in end
        print("msg", message)
        filename = message.split()[1]
        f = open(filename[1:])
        outputdata = f.read()  # Fill in start  #Fill in end
        # Send one HTTP header line into socket
        # Fill in start
        header = ' HTTP/1.1 200 OK\nConnection: close\nContent-Type: text/html\nContent-Length: %d\n\n' % (
            len(outputdata))
        connectionSocket.send(header.encode())

        # Fill in end

        # 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
        # Fill in start
        header = ' HTTP/1.1 404 Found'
        connectionSocket.send(header.encode())
        connectionSocket.close()
        # Fill in end

        # Close client socket
        # Fill in start
        # Fill in end


serverSocket = socket(AF_INET, SOCK_STREAM)
# Prepare a sever socket
# Fill in start
# 定义ip和端口号,然后bind绑定socket
host = ''
port = 6789
serverSocket.bind((host, port))
serverSocket.listen(100)
# Fill in end
while True:
    # Establish the connection
    print('Ready to serve...')
    connectionSocket, addr = serverSocket.accept()
    t = threading.Thread(target=sonTcpConnect, args=(connectionSocket,))
    t.start()
serverSocket.close()

有一个要注意的地方是,在53行,args这个参数的括号内必须要加上逗号,原因是因为args是一个元组,需要在元素后面增加逗号。(资料来源:https://blog.csdn.net/chpllp/article/details/54381141

多次在浏览器请求之后,控制台输出如下:

说实话感觉可能有些bug ,// TODO记得修

进阶题目2:

题目:

不使用浏览器,编写自己的HTTP客户端来测试你的服务器。您的客户端将使用一个TCP连接用于连接到服务器,向服务器发送HTTP请求,并将服务器响应显示出来。您可以假定发送的HTTP请求将使用GET方法。 客户端应使用命令行参数指定服务器IP地址或主机名,服务器正在监听的端口,以及被请求对象在服务器上的路径。以下是运行客户端的输入命令格式。

client.py server_host server_port filename

意思就是用python发送HTTP请求到服务器就可以了。

from socket import *
import sys
clientSocket = socket(AF_INET, SOCK_STREAM)
host = str(sys.argv[1])
port = int(sys.argv[2])

clientSocket.connect((host, port))
msg = 'GET ' + str(sys.argv[3])
clientSocket.send(msg.encode())
result = b""
while True:
    recv_data = clientSocket.recv(1024)
    if recv_data:
        result += recv_data
        if result.rfind(b"0\r\n") != -1:
            break
    else:
        break

print('Received', repr(result))

这里要注意的是,如果没有用While True循环接收,可能只会接收到HTTP响应报文的请求头了。

结果如下: