Python3网络学习案例三:编写web server
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的更多相关文章
- Python3网络学习案例四:编写Web Proxy
代理服务器的定义和作用请走百度百科~ 1. Web Proxy的实现思路 这是基于上一篇"编写Web Server"写的,主要逻辑见下图: 我们要写的就是中间的Web Proxy部 ...
- Python3网络学习案例一:Ping详解
1. 使用Ping做什么 ping用于确定本地主机是否能与另一台主机成功交换(发送与接收)数据包,再根据返回的信息,就可以推断TCP/IP参数是否设置正确,以及运行是否正常.网络是否通畅等. 2. 效 ...
- Python3网络学习案例二:traceroute详解
1. 写在前面 本文是基于上一篇"ping详解"写的: 不同操作系统下的命令也不同,本文仅针对windows系统,命令为"tracert xxx",效果如下 2 ...
- python3.4学习笔记(三) idle 清屏扩展插件
python3.4学习笔记(三) idle 清屏扩展插件python idle 清屏问题的解决,使用python idle都会遇到一个常见而又懊恼的问题——要怎么清屏?在stackoverflow看到 ...
- Java嵌入式数据库H2学习总结(三)——在Web应用中嵌入H2数据库
H2作为一个嵌入型的数据库,它最大的好处就是可以嵌入到我们的Web应用中,和我们的Web应用绑定在一起,成为我们Web应用的一部分.下面来演示一下如何将H2数据库嵌入到我们的Web应用中. 一.搭建测 ...
- ios开发网络学习AFN三:AFN的序列化
#import "ViewController.h" #import "AFNetworking.h" @interface ViewController () ...
- 简易web server之python实现
网络编程一项基本功是socket编程,包括TCP socket,UDP socket的客户端.服务器端编程. 应用层的各路协议如http,smtp,telnet,ftp等都依赖于传输层的TCP或者UD ...
- 自己动手实现网络服务器(Web Server)——基于C#
前言 最近在学习网络原理,突然萌发出自己实现一个网络服务器的想法,并且由于第三代小白机器人的开发需要,我把之前使用python.PHP写的那部分代码都迁移到了C#(别问我为什么这么喜欢C#),之前使用 ...
- python3.4学习笔记(十三) 网络爬虫实例代码,使用pyspider抓取多牛投资吧里面的文章信息,抓取政府网新闻内容
python3.4学习笔记(十三) 网络爬虫实例代码,使用pyspider抓取多牛投资吧里面的文章信息PySpider:一个国人编写的强大的网络爬虫系统并带有强大的WebUI,采用Python语言编写 ...
随机推荐
- Python-去除字符串中不想要的字符
问题: 过滤用户输入中前后多余的空白字符 ' ++++abc123--- ' 过滤某windows下编辑文本中的'\r': 'hello world \r\n' 去掉文本中unicode组 ...
- Spring Cloud系列(三):Eureka源码解析之服务端
一.自动装配 1.根据自动装配原理(详见:Spring Boot系列(二):Spring Boot自动装配原理解析),找到spring-cloud-starter-netflix-eureka-ser ...
- OpenCV 中Scalar
参考来源: 1.https://blog.csdn.net/Eroslol/article/details/52525541 2.https://www.cnblogs.com/hustdc/p/68 ...
- Arduino - 串口操作函数与示例代码大全
来源:https://blog.csdn.net/iracer/article/details/50334041 Arduino - 串口操作函数与示例代码大全 本文总结了Arduino常用串口操作函 ...
- CentOS7.7 系统下 virbr0 虚拟网卡的维护与管理
在 CentOS 7 系统的安装过程中,如果有选择相关虚拟化的的服务安装系统后,启动网卡时会发现有一个以网桥连接的私网地址的 virbr0 网卡,这个是因为在虚拟化中有使用到 libvirtd 服务生 ...
- 线上服务的FGC问题排查
转载:https://blog.csdn.net/g6U8W7p06dCO99fQ3/article/details/106088467 线上服务的GC问题,是Java程序非常典型的一类问题,非常考验 ...
- day49 Pyhton 数据库Mysql 06
多表查询 连表查询 要进行连接,那一定涉及两个表,两个表中要有关联条件才能进行连接 内连接 只有表一和表二中的连接条件都满足的时候才能显示出来 inner join on /where 条件 sele ...
- js拖拽上传 文件上传之拖拽上传
由于项目需要上传文件到服务器,于是便在文件上传的基础上增加了拖拽上传.拖拽上传当然属于文件上传的一部分,只不过在文件上传的基础上增加了拖拽的界面,主要在于前台的交互, 从拖拽的文件中获取文件列表然后调 ...
- HDU - 6736 F - Forest Program
题意 给你n个点m条边,并且保证整个图是仙人掌. 仙人掌:每条边仅属于1条或者0条回路 且无重边和自环 让你删掉一些边使其变成一棵树(拥有点数-1条边) 注意一个点也是森林 图可能是不联通的 思路 考 ...
- fastdfs之同一台storage server下包含多个store path
一,查看本地centos的版本 [root@localhost lib]# cat /etc/redhat-release CentOS Linux release 8.1.1911 (Core) 说 ...