1. 写在前面

这里总结的并不够详细,有时间了再进行补充。

2. 设计思路

HTTP协议是建立在TCP上的
1. 建立服务器端TCP套接字(绑定ip,port),等待监听连接:listen
(2. 打开浏览器(client)访问这个(ip,port),服务器端接收连接:accept)
3. 获取浏览器的请求内容:data = recv(1024)
# 由于浏览器发送的request是HTTP格式的,需要解码
4. 将接收的报文节解码:decode
# 解析解码后的数据
5. 根据行分切数据
6. 解析首部行(header)为:方法,请求路径+文件名
7. 根据解析首部行获取的数据来查找并获取文件内容
8. 构建响应报文(也要是HTTP报文格式的),包括首部行响应信息(200 OK或是file cannot found)
9. 编码响应报文:encode
10. 关闭socket连接

3. 两个版本

3.1 多线程版本

这里采用多线程的方法对每一个请求连接本机的请求建立连接,缺点在于除非关闭服务器程序,否则已建立连接的套接字不会被释放,耗费资源

import socket
import threading def handleReq(clientSocket):
requestData = clientSocket.recv(1024)
requestList = requestData.decode().split("\r\n")
reqHeaderLine = requestList[0]
print("request line: " + reqHeaderLine)
fileName = reqHeaderLine.split(" ")[1].replace("/", "")
try:
file = open("./" + fileName, 'rb') # read the corresponding file from disk
print("fileName: " + fileName) # 查看文件名
except FileNotFoundError:
responseHeader = "HTTP/1.1 404 Not Found\r\n" + \
"Server: 127.0.0.1\r\n" + "\r\n" responseData = responseHeader + "No such file\nCheck your input\n" content = (responseHeader + responseData).encode(encoding="UTF-8") # send the correct HTTP response error
else:
content = file.read() # store in temporary buffer
file.close()
resHeader = "HTTP/1.1 200 OK\r\n"
fileContent01 = "Server: 127.0.0.1\r\n"
fileContent02 = content.decode()
response = resHeader + fileContent01 + "\r\n" + fileContent02 # send the correct HTTP response
clientSocket.sendall(response.encode(encoding="UTF-8")) def startServer(serverAddr, serverPort):
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serverSocket.bind((serverAddr, serverPort))
serverSocket.listen(0)
while True:
try:
print("wait for connecting...")
print("while true")
clientSocket, clientAddr = serverSocket.accept()
print("one connection is established, ", end="")
print("address is: %s" % str(clientAddr))
handleThread = threading.Thread(target=handleReq, args=(clientSocket,))
handleThread.start()
print("client close")
except Exception as err:
print(err)
break
serverSocket.close() # while出错了就关掉 if __name__ == '__main__':
ipAddr = "127.0.0.1"
port = 8000
startServer(ipAddr, port)

3.2 多进程版本

改进了多线程版本的“缺点”

import multiprocessing
import socket def handleReq(clientSocket):
requestData = clientSocket.recv(1024)
requestList = requestData.decode().split("\r\n")
reqHeaderLine = requestList[0]
print("request line: " + reqHeaderLine)
fileName = reqHeaderLine.split(" ")[1].replace("/", "")
try:
file = open("./" + fileName, 'rb') # read the corresponding file from disk
print("fileName: " + fileName) # 查看文件名
except FileNotFoundError:
responseHeader = "HTTP/1.1 404 Not Found\r\n" + \
"Server: 127.0.0.1\r\n" + "\r\n" responseData = responseHeader + "No such file\nCheck your input\n" content = (responseHeader + responseData).encode(encoding="UTF-8") # send the correct HTTP response error
else:
content = file.read() # store in temporary buffer
file.close()
resHeader = "HTTP/1.1 200 OK\r\n"
fileContent01 = "Server: 127.0.0.1\r\n"
fileContent02 = content.decode()
response = resHeader + fileContent01 + "\r\n" + fileContent02 # send the correct HTTP response
clientSocket.sendall(response.encode(encoding="UTF-8")) def startServer(serverAddr, serverPort):
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serverSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serverSocket.bind((serverAddr, serverPort))
serverSocket.listen(0)
while True:
try:
print("wait for connecting...")
print("while true")
clientSocket, clientAddr = serverSocket.accept()
print("one connection is established, ", end="")
print("address is: %s" % str(clientAddr))
handleProcess = multiprocessing.Process(target=handleReq, args=(clientSocket,))
handleProcess.start() # handle request
clientSocket.close()
print("client close")
except Exception as err:
print(err)
break
serverSocket.close() # while出错了就关掉 if __name__ == '__main__':
ipAddr = "127.0.0.1"
port = 8000
startServer(ipAddr, port)

这个版本与多线程版本的区别:

1. 建立套接字时对套接字进行了相关设置【稍后解释】

2. 在开启新进程之后调用“clientSocket.close()”释放资源

对第一点不同的解释

下面解释的来源:https://www.jb51.net/article/50858.htm

python定义了setsockopt()和getsockopt(),一个是设置选项,一个是得到设置。这里主要使用setsockopt(),具体结构如下:

setsockopt(level,optname,value)

level定义了哪个选项将被使用。通常情况下是SOL_SOCKET,意思是正在使用的socket选项。它还可以通过设置一个特殊协议号码来设置协议选项,然而对于一个给定的操作系统,大多数协议选项都是明确的,所以为了简便,它们很少用于为移动设备设计的应用程序。

optname参数提供使用的特殊选项。关于可用选项的设置,会因为操作系统的不同而有少许不同。如果level选定了SOL_SOCKET,那么一些常用的选项见下表:

选项

意义

期望值

SO_BINDTODEVICE

可以使socket只在某个特殊的网络接口(网卡)有效。也许不能是移动便携设备

一个字符串给出设备的名称或者一个空字符串返回默认值

SO_BROADCAST

允许广播地址发送和接收信息包。只对UDP有效。如何发送和接收广播信息包

布尔型整数

SO_DONTROUTE

禁止通过路由器和网关往外发送信息包。这主要是为了安全而用在以太网上UDP通信的一种方法。不管目的地址使用什么IP地址,都可以防止数据离开本地网络

布尔型整数

SO_KEEPALIVE

可以使TCP通信的信息包保持连续性。这些信息包可以在没有信息传输的时候,使通信的双方确定连接是保持的

布尔型整数

SO_OOBINLINE

可以把收到的不正常数据看成是正常的数据,也就是说会通过一个标准的对recv()的调用来接收这些数据

布尔型整数

SO_REUSEADDR

当socket关闭后,本地端用于该socket的端口号立刻就可以被重用。通常来说,只有经过系统定义一段时间后,才能被重用。

布尔型整数

本节在学习时,用到了SO_REUSEADDR选项,具体写法是:

S.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) 这里value设置为1,表示将SO_REUSEADDR标记为TRUE,操作系统会在服务器socket被关闭或服务器进程终止后马上释放该服务器的端口,否则操作系统会保留几分钟该端口。

Python3网络学习案例三:编写web server的更多相关文章

  1. Python3网络学习案例四:编写Web Proxy

    代理服务器的定义和作用请走百度百科~ 1. Web Proxy的实现思路 这是基于上一篇"编写Web Server"写的,主要逻辑见下图: 我们要写的就是中间的Web Proxy部 ...

  2. Python3网络学习案例一:Ping详解

    1. 使用Ping做什么 ping用于确定本地主机是否能与另一台主机成功交换(发送与接收)数据包,再根据返回的信息,就可以推断TCP/IP参数是否设置正确,以及运行是否正常.网络是否通畅等. 2. 效 ...

  3. Python3网络学习案例二:traceroute详解

    1. 写在前面 本文是基于上一篇"ping详解"写的: 不同操作系统下的命令也不同,本文仅针对windows系统,命令为"tracert xxx",效果如下 2 ...

  4. python3.4学习笔记(三) idle 清屏扩展插件

    python3.4学习笔记(三) idle 清屏扩展插件python idle 清屏问题的解决,使用python idle都会遇到一个常见而又懊恼的问题——要怎么清屏?在stackoverflow看到 ...

  5. Java嵌入式数据库H2学习总结(三)——在Web应用中嵌入H2数据库

    H2作为一个嵌入型的数据库,它最大的好处就是可以嵌入到我们的Web应用中,和我们的Web应用绑定在一起,成为我们Web应用的一部分.下面来演示一下如何将H2数据库嵌入到我们的Web应用中. 一.搭建测 ...

  6. ios开发网络学习AFN三:AFN的序列化

    #import "ViewController.h" #import "AFNetworking.h" @interface ViewController () ...

  7. 简易web server之python实现

    网络编程一项基本功是socket编程,包括TCP socket,UDP socket的客户端.服务器端编程. 应用层的各路协议如http,smtp,telnet,ftp等都依赖于传输层的TCP或者UD ...

  8. 自己动手实现网络服务器(Web Server)——基于C#

    前言 最近在学习网络原理,突然萌发出自己实现一个网络服务器的想法,并且由于第三代小白机器人的开发需要,我把之前使用python.PHP写的那部分代码都迁移到了C#(别问我为什么这么喜欢C#),之前使用 ...

  9. python3.4学习笔记(十三) 网络爬虫实例代码,使用pyspider抓取多牛投资吧里面的文章信息,抓取政府网新闻内容

    python3.4学习笔记(十三) 网络爬虫实例代码,使用pyspider抓取多牛投资吧里面的文章信息PySpider:一个国人编写的强大的网络爬虫系统并带有强大的WebUI,采用Python语言编写 ...

随机推荐

  1. 迪杰斯特拉和spfa

    迪杰斯特拉 Dijkstra算法是典型的算法.Dijkstra算法是很有代表性的算法.Dijkstra一般的表述通常有两种方式,一种用永久和临时标号方式,一种是用OPEN, CLOSE表的方式,这里均 ...

  2. Blend学习之Loading加载动画

    介绍: Blend for visual studio 与 visual studio 是有区别的 两者虽然是IDEA 但是专注的方向是不同的,前者是专注UI后者专注业务逻辑,当然你要用blend f ...

  3. Java知识系统回顾整理01基础01第一个程序07Eclipse使用----找不到类如何解决?

    一.现象 有时候会碰到如图所示的问题,分明有Hello这个类,并且也有主方法,可是运行就会出现找不到或者无法加载类Hello,或者Class Not Found 异常. 出现这个状况,有多种原因造成, ...

  4. Tensorflow学习笔记No.1

    使用tf.keras.Sequential()建立网络模型 整个过程可分为五步:1创建Sequential模型,2添加所需要的神经层,3使用.compile方法确定模型训练结构,4使用.fit方法 使 ...

  5. shell-变量的字串应用技术

    1. 变量子串的常用操作 常用操作如下表: 依次举例说明: 定义aa变量,内容为"I am scajy" [root@1-241 script]# aa="I am sc ...

  6. 多测师讲解a'pi自动化框架设计思想_高级讲师肖sir

    API自动化框架API自动化框架分为conf.data.utils.api.testcase.runner.report.log8个模块.conf是用来储存系统环境.数据库.邮件等的配置参数.项目的绝 ...

  7. mqtt网关

    MQTT网关 MQTT网关是可以是将普通的串口数据.Modbus RTU数据等转化为MQTT协议的从而方便与平台的对接,通过连接服务器.订阅和发布主题来实现传统设备和MQTT云端的联系.例如,笔记本和 ...

  8. 【转载】opencvVS2019配置方法

    环境: 系统:win10系统截至2020920版本 opencv版本:3.0.0版本 IDE:宇宙最强IDEA最新版本2019社区版 教程: 1.下载opencv安装包官网下载链接:https://o ...

  9. 带权二分图最大匹配KM算法

    二分图的判定 如果一个图是连通的,可以用如下的染色法判定是否二分图: 我们把X部的结点颜色设为0,Y部的颜色设为1. 从某个未染色的结点u开始,做BFS或者DFS .把u染为0,枚举u的儿子v.如果v ...

  10. 【KM算法】UVA 11383 Golden Tiger Claw

    题目大意 给你一个\(n×n\)的矩阵G,每个位置有一个权,求两个一维数组\(row\)和\(col\),使\(row[i] + col[j]\ge G[i][j]\),并且\(∑row+∑col\) ...