☀️苏州程序大白用万字解析Python网络编程与Web编程☀️《❤️记得收藏❤️》

☀️苏州程序大白用万字解析Python网络编程☀️《❤️记得收藏❤️》

  • 目录
  • ️‍开讲啦!!!!️‍苏州程序大白️‍
  • 博主介绍
  • 计算机网络基础
    • IP地址的介绍
  • 端口和端口号
  • 协议
  • TCP网络开发流程
    • TCP客户端程序开发流程
    • TCP服务端程序开发流程
  • TCP网络开发
    • socket类
    • TCP客户端程序开发
    • TCP服务端程序开发
    • 网络开发注意点
  • socket中 send 与 recv原理剖析
  • HTTP协议
  • 什么是URL
  • HTTP请求报文
    • GET请求报文
    • POST请求报文
    • POST与GET之间的区别
  • HTTP响应报文
    • HTTP响应报文
    • 常见HTTP状态码
  • 使用Python自带的HTTP服务器
    • 静态web服务器是什么
    • 如何搭建Python自带的静态Web服务器
  • 自制静态Web服务器
  • 作者相关的文章、资源分享

目录

️‍开讲啦!!!!️‍苏州程序大白️‍

☀️苏州程序大白用万字解析Python网络编程与Web编程☀️《❤️记得收藏❤️》_第1张图片

博主介绍

个人主页:苏州程序大白

作者介绍:中国DBA联盟(ACDU)成员,CSDN全国各地程序猿(媛)聚集地管理员。目前从事工业自动化软件开发工作。擅长C#、Java、机器视觉、底层算法等语言。2019年成立柒月软件工作室。

如果文章对你有帮助,欢迎关注、点赞、收藏(一键三连)和C#、Halcon、python+opencv、VUE、各大公司面试等一些订阅专栏哦

️ 承接各种软件开发项目

有任何问题欢迎私信,看到会及时回复

微信号:stbsl6,微信公众号:苏州程序大白

想加入技术交流群的可以加我好友,群里会分享学习资料

计算机网络基础

IP地址的介绍

IP地址的概念:

  • IP地址(Internet Protocol Address)是指互联网协议地址,又译为网际协议地址。

  • IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。
    ☀️苏州程序大白用万字解析Python网络编程与Web编程☀️《❤️记得收藏❤️》_第2张图片
    IP地址的表现形式:

  • IP 地址分为两类: IPv4 和 IPv6。

  • IPv4 是普遍正在被广泛使用的IP协议。

  • IPv6 是现阶段为了解决IPv4地址不够用的情况而正在普及的下一代IP协议。

  • IPv4 是由点分十进制组成。

  • IPv6 是由冒号十六进制组成。

IP地址的作用:

  • IP 地址的作用是标识网络中唯一的一台设备的,也就是说通过IP地址能够找到网络中某台设备。
    ☀️苏州程序大白用万字解析Python网络编程与Web编程☀️《❤️记得收藏❤️》_第3张图片
    查看IP地址:

  • Linux 和 mac OS 使用 ifconfig 这个命令。

☀️苏州程序大白用万字解析Python网络编程与Web编程☀️《❤️记得收藏❤️》_第4张图片

  • Windows 使用 ipconfig 这个命令
    ☀️苏州程序大白用万字解析Python网络编程与Web编程☀️《❤️记得收藏❤️》_第5张图片

端口和端口号

什么是端口、什么是端口号

  • 即为数据传输的通道,若将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的作用
    进程之间网络数据传输。

☀️苏州程序大白用万字解析Python网络编程与Web编程☀️《❤️记得收藏❤️》_第6张图片

TCP网络开发流程

☀️苏州程序大白用万字解析Python网络编程与Web编程☀️《❤️记得收藏❤️》_第7张图片

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_STREAMSOCK_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原理剖析

☀️苏州程序大白用万字解析Python网络编程与Web编程☀️《❤️记得收藏❤️》_第8张图片
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服务器的通讯过程

☀️苏州程序大白用万字解析Python网络编程与Web编程☀️《❤️记得收藏❤️》_第9张图片

什么是URL

什么是URL:

1、URL的英文全拼是(Uniform Resoure Locator),表达的意思是统一资源定位符,通俗理解就是网络资源地址,也就是我们常说的网址。

  • URL的组成

URL的样子:
☀️苏州程序大白用万字解析Python网络编程与Web编程☀️《❤️记得收藏❤️》_第10张图片
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之间的区别

☀️苏州程序大白用万字解析Python网络编程与Web编程☀️《❤️记得收藏❤️》_第11张图片

  • 一个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响应报文是由以下部分组成的:

☀️苏州程序大白用万字解析Python网络编程与Web编程☀️《❤️记得收藏❤️》_第12张图片

常见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

☀️苏州程序大白用万字解析Python网络编程与Web编程☀️《❤️记得收藏❤️》_第13张图片

自制静态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编程基础问答❤️《记得收藏不然看着看着就不见了》

✨有关各大公司面试题、面试流程欢迎各位查看个人主页✨

☀️苏州程序大白用万字解析Python网络编程与Web编程☀️《❤️记得收藏❤️》_第14张图片

❤️关注苏州程序大白公众号❤️



你可能感兴趣的:(Python,python,面试,web,网络)