☀️苏州程序大白用万字解析Python网络编程☀️《❤️记得收藏❤️》
目录
🏳️🌈开讲啦!!!!🏳️🌈苏州程序大白🏳️🌈 |
🌟博主介绍
💂 个人主页:苏州程序大白
🤟作者介绍:中国DBA联盟(ACDU)成员,CSDN全国各地程序猿(媛)聚集地管理员。目前从事工业自动化软件开发工作。擅长C#、Java、机器视觉、底层算法等语言。2019年成立柒月软件工作室。
💬如果文章对你有帮助,欢迎关注、点赞、收藏(一键三连)和C#、Halcon、python+opencv、VUE、各大公司面试等一些订阅专栏哦
🎗️ 承接各种软件开发项目
💅 有任何问题欢迎私信,看到会及时回复
👤 微信号:stbsl6,微信公众号:苏州程序大白
🎯 想加入技术交流群的可以加我好友,群里会分享学习资料
计算机网络基础
IP地址的介绍
IP地址的概念:
-
IP地址(Internet Protocol Address)是指互联网协议地址,又译为网际协议地址。
-
IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。
IP地址的表现形式: -
IP 地址分为两类: IPv4 和 IPv6。
-
IPv4 是普遍正在被广泛使用的IP协议。
-
IPv6 是现阶段为了解决IPv4地址不够用的情况而正在普及的下一代IP协议。
-
IPv4 是由点分十进制组成。
-
IPv6 是由冒号十六进制组成。
IP地址的作用:
-
IP 地址的作用是标识网络中唯一的一台设备的,也就是说通过IP地址能够找到网络中某台设备。
查看IP地址: -
Linux 和 mac OS 使用
ifconfig
这个命令。
- Windows 使用 ipconfig 这个命令
端口和端口号
什么是端口、什么是端口号
-
即为数据传输的通道,若将IP地址比作一座房子的地址 ,那么端口就是出入房子的门;
-
然而真正的房子只有几个门,但是一个IP地址的端口可以有65536个;
-
端口是通过端口号来标记的,端口号只有整数,范围是从0 到65535。
端口号的分类
-
知名端口:0 - 1023。
-
动态端口:1024 - 65535。
协议
TCP协议
-
TCP的概念
-
传输控制协议(Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。
TCP通信流程
1、建立连接(三次握手)。
2、传输数据。
3、关闭连接(四次挥手)。
TCP的特点
-
面向连接。
-
可靠传输。
UDP协议
- 概念:用户数据报协议(User Datagram Protocol)是OSI参考模型中一种无连接的传输层协议。
UDP的特点
-
面向报文。
-
无连接。
-
吞吐量不受拥挤控制算法的调节。
socket
-
什么是socket?
网络套接字(英语:Network socket;又译网络套接字、网络接口、网络插槽)在计算机科学中是电脑网络中进程间数据流的端点,是一种操作系统提供的进程间通信机制。 -
socket的作用
进程之间网络数据传输。
TCP网络开发流程
TCP客户端程序开发流程
- 流程梳理:
1、创建服务端套接字对象。
2、绑定监听端口。
3、设置监听。
4、等待客户端的连接请求。
5、接受数据。
6、返回数据。
7、关闭套接字。
TCP服务端程序开发流程
- 流程梳理:
1、创建客户端套接字对象。
2、和服务端套接字建立连接。
3、发送数据。
4、接受数据。
5、关闭客户端套接字。
TCP网络开发
socket类
Python 中,我们用 socket()函数来创建套接字,语法格式如下:
import socket
socket.socket([family[, type[, proto]]])
- 参数:
参数 | 描述 |
---|---|
family | 套接字家族可以使AF_UNIX或者AF_INET |
family | 套接字家族可以使AF_UNIX或者AF_INET |
type | 套接字类型可以根据是面向连接的还是非连接分为SOCK_STREAM 或SOCK_DGRAM |
protocol | 一般不填默认为0 |
- Socket 类型:
类型 | 描述 |
---|---|
socket.AF_UNIX | 只能够用于单一的Unix系统进程间通信 |
socket.AF_INET | 服务端与客户端之间通讯协议(IPv4) |
socket.AF_INET6 | 服务端与客户端之间通讯协议(IPv6) |
socket.SOCK_STREAM | 使用TCP传输协议进行数据传输(流式socket) |
socket.SOCK_DGRAM | 使用UDP传输协议进行数据传输(数据报式socket) |
socket.SOCK_RAW | 原始套接字;可以处理普通套接字无法处理的ICMP,IGMP等特殊的网络报文 |
socket.SOCK_RDM | 提供可靠的UDP数据报连接,即保证交付数据报但不保证数据 |
socket.SOCK_SEQPACKET | 提供连续可靠的数据包连接 |
- socket类方法:
方法 | 描述 |
---|---|
_socket.bind(address) | 将套接字绑定到地址;在AF_INET下,以元组(host,port)的形式表示地址。 |
_socket.listen(backlog) | 开始监听传入连接。backlog指定在拒绝连接之前,可以挂起的最大连接数量。 |
_socket.setblocking(bool) | 是否阻塞(默认True),如果设置False,那么accept和recv时一旦无数据,则报错。 |
_socket.accept() | 接受连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据。address是客户端的地址。 |
_socket.connect(address) | 连接到address处的套接字。一般情况下address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。 |
_socket.connect_ex(address) | 同上,只不过会有返回值,连接成功时返回 0 ,连接失败时候返回错误代码 |
_socket.close() | 关闭套接字连接 |
_socket.recv(bufsize[,flag]) | 接受套接字的数据。数据以字符串形式返回,bufsize指定最多可以接收的数量。flag提供有关消息的其他信息,通常可以忽略。 |
_socket.recvfrom(bufsize[.flag]) | 与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。 |
_socket.send(string[,flag]) | 将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。即:可能未将指定内容全部发送。 |
_socket.sendall(string[,flag]) | 将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。内部通过递归调用send,将所有内容发送出去。 |
_socket.sendto(string[,flag],address) | 将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。该函数主要用于UDP协议。 |
_socket.settimeout(timeout) | 设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。 |
_socket.getpeername() | 返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。 |
_socket.getsockname() | 返回套接字自己的地址。通常是一个元组(ipaddr,port) |
_socket.fileno() | 套接字的文件描述符 |
TCP客户端程序开发
import socket # 导入socket包
if __name__ == '__main__':
# 创建socket套接字 AF_INET -> 采用IPv4 ;SOCK_STREAM -> 采用TCP传输协议
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 与服务端建立连接
client_socket.connect(('127.0.0.1', 9091))
# 准备需要发送的数据,使用UTF-8进行编码
_data = 'Connect Succces!'.encode('utf-8')
# 发送数据
client_socket.send(_data)
# 获取服务端返回数据
_recv = client_socket.recv(1024)
# 打印服务端返回的原始数据
print('获得来自服务器的原始数据:', _recv)
# 对数据进行解码
_decode = _recv.decode('utf-8')
print('获得来自服务器的数据:', _decode)
# 关闭socket套接字
client_socket.close()
TCP服务端程序开发
单任务版:
import socket # 导入socket包
if __name__ == '__main__':
# 创建socket套接字 AF_INET -> 采用IPv4 ;SOCK_STREAM -> 采用TCP传输协议
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置启用端口复用,当程序结束时,立即释放端口号
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 绑定监听端口号
server_socket.bind(("0.0.0.0", 9091))
# 配置监听最大等待连接个数
server_socket.listen(128)
# 等待客户端建立连接请求,返回(conn,info),若无连接则会一直保持阻塞状态
# 其中conn由service_socket接收,是与客户端建立连接的套接字
# info由client_info接收,是客户端的地址与端口信息
service_socket, client_info = server_socket.accept()
print('客户端的IP地址和端口号:', client_info)
# 获取客户端发送的原始数据
_renv = service_socket.recv(1024)
# 获取原始数据的长度
_length = len(_renv)
print('接收数据的长度为:', _length)
# 对原始数据进行解码
_decode = _renv.decode('utf-8')
print('接收客户端的数据为:', _decode)
# 准备需要返回的数据,使用UTF-8进行编码
_data = '问题处理中...'.encode('utf-8')
# 发送数据
service_socket.send(_data)
# 关闭服务端与客户端的套接字
service_socket.close()
# 关闭服务端套接字
server_socket.close()
多任务版:
在现实生产环境中,一个服务端不可能只就服务于一个客户端;通常一个服务端是要能服务多个客户端,以下是多任务的实现思路:
1、编写一个TCP服务端程序,循环等待接受客户端的连接请求。
2、当客户端和服务端建立连接成功,创建子线程,使用子线程专门处理客户端的请求,防止主线程阻塞。
3、把创建的子线程设置成为守护主线程,防止主线程无法退出。
import socket
import threading
# 客户端服务处理函数
def handle_client_request(_socket, _info):
while True:
# 获取客户端发送的原始数据
_data = _socket.recv(1024)
# 容器类型判断是否有数据可以直接使用if语句进行判断,如果容器类型里面有数据表示条件成立,否则条件失败
# 容器类型: 列表、字典、元组、字符串、set、range、二进制数据
if _data:
print(_data.decode("utf-8"), _info)
# 回复
_socket.send("数据接收正常...".encode("utf-8"))
else:
print("客户端下线了:", _info)
break
# 关闭服务端与客户端的套接字
_socket.close()
if __name__ == '__main__':
# 创建socket套接字 AF_INET -> 采用IPv4 ;SOCK_STREAM -> 采用TCP传输协议
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置启用端口复用,当程序结束时,立即释放端口号
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 绑定监听端口号
tcp_server_socket.bind(("", 9090))
# 配置监听最大等待连接个数
tcp_server_socket.listen(128)
# 循环等待接收客户端的连接请求
while True:
# 等待客户端建立连接请求,返回(conn,info),若无连接则会一直保持阻塞状态
# 其中conn由service_socket接收,是与客户端建立连接的套接字
# info由client_info接收,是客户端的地址与端口信息
service_socket, client_info = tcp_server_socket.accept()
print("客户端连接成功:", client_info)
# 当客户端和服务端建立连接成功以后,创建一个子线程处理接下来的客户端讯息
client_thread = threading.Thread(target=handle_client_request, args=(service_socket, client_info))
# 设置守护主线程,当主线程退出时自动终止子线程
client_thread.setDaemon(True)
# 启动子线程
client_thread.start()
网络开发注意点
1、当 TCP 客户端程序想要和 TCP 服务端程序进行通信的时候必须要先建立连接。
2、TCP 客户端程序一般不需要绑定端口号,因为客户端是主动发起建立连接的。
3、TCP 服务端程序必须绑定端口号,否则客户端找不到这个 TCP 服务端程序。
4、listen 后的套接字是被动套接字,只负责接收新的客户端的连接请求,不能收发消息。
5、当 TCP 客户端程序和 TCP 服务端程序连接成功后, TCP 服务器端程序会产生一个新的套接字,收发客户端消息使用该套接字。
6、关闭 accept 返回的套接字意味着和这个客户端已经通信完毕。
7、关闭 listen 后的套接字意味着服务端的套接字关闭了,会导致新的客户端不能连接服务端,但是之前已经接成功的客户端还能正常通信。
8、当客户端的套接字调用 close 后,服务器端的 recv 会解阻塞,返回的数据长度为0,服务端可以通过返回数据的长度来判断客户端是否已经下线,反之服务端关闭套接字,客户端的 recv 也会解阻塞,返回的数据长度也为0。
socket中 send 与 recv原理剖析
send
原理
Q:send是不是直接把数据发给服务端?
A:不是,要想发数据,必须得通过网卡发送数据,应用程序是无法直接通过网卡发送数据的,它需要调用操作系统接口,也就是说,应用程序把发送的数据先写入到发送缓冲区(内存中的一片空间),再由操作系统控制网卡把发送缓冲区的数据发送给服务端网卡 。
recv
原理
Q:renv是不是直接从客户端接收数据?
A:不是,应用软件是无法直接通过网卡接收数据的,它需要调用操作系统接口,由操作系统通过网卡接收数据,把接收的数据写入到接收缓冲区(内存中的一片空间),应用程序再从接收缓存区获取客户端发送的数据。
HTTP协议
什么是HTTP协议
- HTTP协议介绍:
1、HTTP 协议的全称是(HyperText Transfer Protocol),翻译过来就是超文本传输协议。
2、超文本是超级文本的缩写,是指超越文本限制或者超链接,比如:图片、音乐、视频、超链接等等都属于超文本。
3、HTTP 协议的制作者是蒂姆·伯纳斯-李,1991年设计出来的,HTTP 协议设计之前目的是传输网页数据的,现在允许传输任意类型的数据。
4、传输 HTTP 协议格式的数据是基于 TCP 传输协议的,发送数据之前需要先建立连接。
- HTTP协议的作用:
1、规定浏览器和web服务器通信的数据格式。
- 浏览器访问Web服务器的通讯过程
什么是URL
什么是URL:
1、URL的英文全拼是(Uniform Resoure Locator),表达的意思是统一资源定位符,通俗理解就是网络资源地址,也就是我们常说的网址。
- URL的组成
URL的样子:
URL的组成部分:
1、协议部分: https://
、http://
、ftp://
。
2、域名部分: news.163.com。
3、资源路径部分: /18/1122/10/E178J2O4000189FH.html。
域名:
- 域名就是IP地址的别名,它是用点进行分割使用英文字母和数字组成的名字,使用域名目的就是方便的记住某台主机IP地址。
URL的扩展:
-
model遵守Codable协议。
-
用JSONEncoder进行解析。
定义ConvertToStringable协议
protocol ConvertToStringable {
associatedtype Result: Codable
var valueString: String { get }
}
extension ConvertToStringable {
func toString(result: Result) -> String {
let data = try? JSONEncoder().encode(result)
guard let da = data else { return "" }
guard let st = String.init(data: da, encoding: .utf8) else { return "" }
return st
}
}
我们使用关联类型来匹配不同的模型实例,然后我们在每个需要model转为JSON格式字符串的model里扩展一下model:
struct UserInfo: Codable {
var name: String
var age: Int
var avator: String
}
extension UserInfo: ConvertToStringable {
typealias Result = UserInfo
var valueString: String { return toString(result: self) }
}
查询参数部分: ?page=1&count=10
- 参数说明:
?
后面的 page
表示第一个参数,后面的参数都使用 &
进行连接。
HTTP请求报文
GET请求报文
---- 请求行 ----
GET / HTTP/1.1 # GET请求方式 请求资源路径 HTTP协议版本
---- 请求头 -----
Host: www.smartfox.cc # 服务器的主机地址和端口号,默认是80
Connection: keep-alive # 和服务端保持长连接
Upgrade-Insecure-Requests: 1 # 让浏览器升级不安全请求,使用https请求
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36 # 用户代理,也就是客户端的名称
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 # 可接受的数据类型
Accept-Encoding: gzip, deflate # 可接受的压缩格式
Accept-Language: zh-CN,zh;q=0.9 #可接受的语言
Cookie: csrftoken=ZIVKMSEdmdJbowTnXtRPXByIqxK1WF1ronGQXKWdp51WnSvmlRyqsKzZFPAojcLF; sessionid=as3sop6t2igilg76zll45m045udfsoa7; # 登录用户的身份标识
---- 空行 ----
也就是说GET请求报文是由以下部分组成的:
-
请求行。
-
请求头。
-
空行。
POST请求报文
---- 请求行 ----
POST /admin.php?next=index.php HTTP/1.1 # POST请求方式 请求资源路径 HTTP协议版本
---- 请求头 ----
Host: www.smartfox.cc # 服务器的主机地址和端口号,默认是80
Connection: keep-alive # 和服务端保持长连接
Content-Type: application/x-www-form-urlencoded # 告诉服务端请求的数据类型
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36 # 客户端的名称
---- 空行 ----
---- 请求体 ----
username=admin&pass=admin # 请求参数
也就是说POST报文是由以下部分组成:
-
请求行
-
请求头
-
空行
-
请求体
POST与GET之间的区别
-
一个HTTP请求报文可以由请求行、请求头、空行和请求体4个部分组成。
-
GET方式的请求报文没有请求体,只有请求行、请求头、空行组成。
-
POST方式的请求报文可以有请求行、请求头、空行、请求体四部分组成。
注意:POST方式可以允许没有请求体,但是这种格式很少见。
HTTP响应报文
HTTP响应报文
--- 响应行/状态行 ---
HTTP/1.1 200 OK # HTTP协议版本 状态码 状态描述
--- 响应头 ---
Server: Tengine # 服务器名称
Content-Type: text/html; charset=UTF-8 # 内容类型
Transfer-Encoding: chunked # 发送给客户端内容不确定内容长度,发送结束的标记是0\r\n, Content-Length表示服务端确定发送给客户端的内容大小,但是二者只能用其一。
Connection: keep-alive # 和客户端保持长连接
Date: Fri, 23 Nov 2018 02:01:05 GMT # 服务端的响应时间
--- 空行 ---
--- 响应体 ---
<!DOCTYPE html><html lang=“en”>…</html> # 响应给客户端的数据
所以一个成熟的HTTP响应报文是由以下部分组成的:
常见HTTP状态码
状态码 | 状态 | 说明 |
---|---|---|
200 | OK | 请求成功 |
201 | Created | 请求已经被实现,而且所需资源已建立,且其URI已经随头部信息返回。 |
202 | Accepted | 服务器已接受请求,但尚未处理。 |
307 | Temporary Redirect | 重定向 |
400 | Bad Request | 错误的请求,请求地址或者参数有误 |
403 | Forbidden | 服务器已经理解请求,但是拒绝执行它。 |
404 | Not Found | 请求资源在服务器不存在 |
500 | Internal Server Error | 服务器内部源代码出现错误 |
502 | Bad Gateway | 作为网关或代理的服务器尝试执行请求时,从上游服务接到无效的响应。 |
使用Python自带的HTTP服务器
静态web服务器是什么
-
可以为发出请求的浏览器提供静态文档的程序。
-
平时我们浏览百度新闻数据的时候,每天的新闻数据都会发生变化,那访问的这个页面就是动态的,而我们开发的是静态的,页面的数据不会发生变化。
如何搭建Python自带的静态Web服务器
在Python3的模块中,官方加入了http模块,我们可以直接调用运行它,让他作为提供静态Web的服务。
-
语法格式:
python3 -m http.server [PORT]
。 -
-m
表示运行包里面的模块。 -
执行这个命令的时候,需要进入你自己指定静态文件的目录,然后通过浏览器就能访问对应的静态文件了。
python3 -m http.server 8080
自制静态Web服务器
返回固定页面数据
import socket
if __name__ == '__main__':
_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
_server.bind(("", 9091))
_server.listen(10)
while True:
_client, _client_info = _server.accept()
_request_data = _client.recv(4096)
print(_request_data)
with open("static/index.html", 'rb') as _file:
file_data = _file.read()
print(file_data)
response_line = "HTTP/1.1 200 OK\r\n"
response_head = "Server: NGINX/14.8\r\n"
response_body = file_data
response_data = (response_line + response_head + "\r\n").encode('utf-8') + response_body
print(response_data)
_client.send(response_data)
_client.close()
返回指定页面数据
import socket
def init_server():
_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
_server.bind(("", 9091))
print("Server Listen : 0.0.0.0:9091")
_server.listen(128)
return _server
def service_logic(_server):
_service, _info = _server.accept()
renv_data = _service.recv(4096)
if len(renv_data) == 0:
print('客户端', _info, '离线')
_service.close()
return
_data = renv_data.decode('utf-8')
url = _data.split(" ", maxsplit=2)
uri = url[1]
print(uri)
if uri == "/":
uri = '/index.html'
try:
with open("static" + uri, "rb") as _file:
response_body = _file.read()
except Exception as e:
response_line = "HTTP/1.1 404 Not Found\r\n"
response_header = "Server: PythonWeb1.0\r\n"
with open("static/error.html", "rb") as _file:
response_body = _file.read()
response_data = (response_line + response_header + "\r\n").encode("utf-8") + response_body
_service.send(response_data)
else:
response_line = "HTTP1.1 200 OK\r\n"
response_header = "Server: PythonWeb1.0\r\n"
response_data = (response_line + response_header + "\r\n").encode('utf-8') + response_body
_service.send(response_data)
finally:
_service.close()
if __name__ == '__main__':
server = init_server()
while True:
service_logic(server)
多任务版
import socket
import threading
def init_server():
_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
_server.bind(("", 9091))
print("Server Listen : 0.0.0.0:9091")
_server.listen(128)
return _server
def handle_client(_service, _info):
renv_data = _service.recv(4096)
if len(renv_data) == 0:
print('客户端', _info, '离线')
_service.close()
return
_data = renv_data.decode('utf-8')
url = _data.split(" ", maxsplit=2)
uri = url[1]
print(uri)
if uri == "/":
uri = '/index.html'
try:
with open("static" + uri, "rb") as _file:
response_body = _file.read()
except Exception as e:
response_line = "HTTP/1.1 404 Not Found\r\n"
response_header = "Server: PythonWeb1.0\r\n"
with open("static/error.html", "rb") as _file:
response_body = _file.read()
response_data = (response_line + response_header + "\r\n").encode("utf-8") + response_body
_service.send(response_data)
else:
response_line = "HTTP1.1 200 OK\r\n"
response_header = "Server: PythonWeb1.0\r\n"
response_data = (response_line + response_header + "\r\n").encode('utf-8') + response_body
_service.send(response_data)
finally:
_service.close()
def service_logic(_server):
_services, _info = _server.accept()
handle_service = threading.Thread(target=handle_client, args=(_services, _info))
handle_service.daemon = True
handle_service.start()
if __name__ == '__main__':
server = init_server()
while True:
service_logic(server)
面向对象版
import socket
import threading
class WebServer(object):
def __init__(self, addr: str = '0.0.0.0', port: int = 9091) -> None:
self._server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
self._server.bind((addr, port))
print(f"Server Listen!{addr}:{port}")
self._server.listen(128)
def service_logic(self) -> None:
while True:
_services, _info = self._server.accept()
handle_service = threading.Thread(target=self.handle_client, args=(_services, _info))
handle_service.daemon = True
handle_service.start()
@staticmethod
def handle_client(_service: socket.socket, _info: tuple) -> None:
renv_data = _service.recv(4096)
if len(renv_data) == 0:
print('客户端', _info, '离线')
_service.close()
return
_data = renv_data.decode('utf-8')
url = _data.split(" ", maxsplit=2)
uri = url[1]
print(uri)
if uri == "/":
uri = '/index.html'
try:
with open("static" + uri, "rb") as _file:
response_body = _file.read()
except Exception as e:
response_line = "HTTP/1.1 404 Not Found\r\n"
response_header = "Server: PythonWeb1.0\r\n"
with open("static/error.html", "rb") as _file:
response_body = _file.read()
response_data = (response_line + response_header + "\r\n").encode("utf-8") + response_body
_service.send(response_data)
else:
response_line = "HTTP1.1 200 OK\r\n"
response_header = "Server: PythonWeb1.0\r\n"
response_data = (response_line + response_header + "\r\n").encode('utf-8') + response_body
_service.send(response_data)
finally:
_service.close()
if __name__ == '__main__':
server = WebServer()
server.service_logic()
命令行启动动态绑定端口号
import socket
import threading
import sys
class WebServer(object):
def __init__(self, addr: str = '0.0.0.0', port: int = 9091) -> None:
self._server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
self._server.bind((addr, port))
print(f"Server Listen!{addr}:{port}")
self._server.listen(128)
def service_logic(self) -> None:
while True:
_services, _info = self._server.accept()
handle_service = threading.Thread(target=self.handle_client, args=(_services, _info))
handle_service.daemon = True
handle_service.start()
@staticmethod
def handle_client(_service: socket.socket, _info: tuple) -> None:
renv_data = _service.recv(4096)
if len(renv_data) == 0:
print('客户端', _info, '离线')
_service.close()
return
_data = renv_data.decode('utf-8')
url = _data.split(" ", maxsplit=2)
uri = url[1]
print(uri)
if uri == "/":
uri = '/index.html'
try:
with open("static" + uri, "rb") as _file:
response_body = _file.read()
except Exception as e:
response_line = "HTTP/1.1 404 Not Found\r\n"
response_header = "Server: PythonWeb1.0\r\n"
with open("static/error.html", "rb") as _file:
response_body = _file.read()
response_data = (response_line + response_header + "\r\n").encode("utf-8") + response_body
_service.send(response_data)
else:
response_line = "HTTP1.1 200 OK\r\n"
response_header = "Server: PythonWeb1.0\r\n"
response_data = (response_line + response_header + "\r\n").encode('utf-8') + response_body
_service.send(response_data)
finally:
_service.close()
if __name__ == '__main__':
args = sys.argv
if len(sys.argv) != 2:
print("执行命令如下: python3 xxx.py 8000")
exit(0)
# 判断字符串是否都是数字组成
if not sys.argv[1].isdigit():
print("执行命令如下: python3 xxx.py 8000")
exit(0)
port = int(sys.argv[1])
server = WebServer(port=port)
server.service_logic()
🌟作者相关的文章、资源分享🌟
🌟让天下没有学不会的技术🌟
学习C#不再是难问题
🌳《C#入门到高级教程》🌳
有关C#实战项目
👉C#RS232C通讯源码👈
👉C#委托数据传输👈
👉C# Modbus TCP 源代码👈
👉C# 仓库管理系统源码👈
👉C# 欧姆龙通讯Demo👈
👉C#+WPF+SQL目前在某市上线的车管所摄像系统👈
👉2021C#与Halcon视觉通用的框架👈
👉2021年视觉项目中利用C#完成三菱PLC与上位机的通讯👈
👉VP联合开源深度学习编程(WPF)👈
✨有关C#项目欢迎各位查看个人主页✨
🌟机器视觉、深度学习🌟
学习机器视觉、深度学习不再是难问题
🌌《Halcon入门到精通》🌌
🌌《深度学习资料与教程》🌌
有关机器视觉、深度学习实战
👉2021年C#+HALCON视觉软件👈
👉2021年C#+HALCON实现模板匹配👈
👉C#集成Halcon的深度学习软件👈
👉C#集成Halcon的深度学习软件,带[MNIST例子]数据集👈
👉C#支持等比例缩放拖动的halcon WPF开源窗体控件👈
👉2021年Labview联合HALCON👈
👉2021年Labview联合Visionpro👈
👉基于Halcon及VS的动车组制动闸片厚度自动识别模块👈
✨有关机器视觉、深度学习实战欢迎各位查看个人主页✨
🌟Java、数据库教程与项目🌟
学习Java、数据库教程不再是难问题
🍏《JAVA入门到高级教程》🍏
🍏《数据库入门到高级教程》🍏
有关Java、数据库项目实战
👉Java经典怀旧小霸王网页游戏机源码增强版👈
👉js+css类似网页版网易音乐源码👈
👉Java物业管理系统+小程序源码👈
👉JavaWeb家居电子商城👈
👉JAVA酒店客房预定管理系统的设计与实现SQLserver👈
👉JAVA图书管理系统的研究与开发MYSQL👈
✨有关Java、数据库教程与项目实战欢迎各位查看个人主页✨
🌟分享Python知识讲解、分享🌟
学习Python不再是难问题
🥝《Python知识、项目专栏》🥝
🥝《Python 检测抖音关注账号是否封号程》🥝
🥝《手把手教你Python+Qt5安装与使用》🥝
🥝《用一万字给小白全面讲解python编程基础问答》🥝
🥝《Python 绘制Android CPU和内存增长曲线》🥝
有关Python项目实战
👉Python基于Django图书管理系统👈
👉Python管理系统👈
👉2021年9个常用的python爬虫源码👈
👉python二维码生成器👈
✨有关Python教程与项目实战欢迎各位查看个人主页✨
🌟分享各大公司面试题、面试流程🌟
面试成功不是难事
🍏《2021年金九银十最新的VUE面试题☀️《❤️记得收藏❤️》》🍏
🍏《只要你认真看完一万字☀️Linux操作系统基础知识☀️分分钟钟都吊打面试官《❤️记得收藏❤️》》🍏
🍏《❤️用一万字给小白全面讲解python编程基础问答❤️《😀记得收藏不然看着看着就不见了😀》》🍏
✨有关各大公司面试题、面试流程欢迎各位查看个人主页✨