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

Posted 苏州程序大白

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了☀️苏州程序大白用万字解析Python网络编程与Web编程☀️《❤️记得收藏❤️》相关的知识,希望对你有一定的参考价值。

目录

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

🌟博主介绍

💂 个人主页:苏州程序大白

🤟作者介绍:中国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_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原理剖析


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状态码

状态码状态说明
200OK请求成功
201Created请求已经被实现,而且所需资源已建立,且其URI已经随头部信息返回。
202Accepted服务器已接受请求,但尚未处理。
307Temporary Redirect重定向
400Bad Request错误的请求,请求地址或者参数有误
403Forbidden服务器已经理解请求,但是拒绝执行它。
404Not Found请求资源在服务器不存在
500Internal Server Error服务器内部源代码出现错误
502Bad 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以上是关于☀️苏州程序大白用万字解析Python网络编程与Web编程☀️《❤️记得收藏❤️》的主要内容,如果未能解决你的问题,请参考以下文章

☀️苏州程序大白解析Linux 中的虚拟网络接口☀️《❤️记得收藏❤️》

☀️苏州程序大白解析Linux 中的虚拟网络接口☀️《❤️记得收藏❤️》

☀️苏州程序大白一文解析Java多线程☀️《❤️记得收藏❤️》

☀️苏州程序大白一文从基础手把手教你Python数据可视化大佬☀️《❤️记得收藏❤️》

苏州程序大白总结Vue零基础到高阶第一节☀️《❤️记得收藏❤️》

苏州程序大白总结Vue零基础到高阶第二节☀️《❤️记得收藏❤️》