首页 > 编程语言 >十天学会Python——第9天:多任务编程与网络编程

十天学会Python——第9天:多任务编程与网络编程

时间:2024-07-20 09:27:49浏览次数:17  
标签:__ socket Python 编程 tcp 线程 进程 多任务 客户端

1 进程与线程

1.1 多进程基础

  • 并发:一段时间内交替执行多个任务(任务数量大于CPU核心数)
  • **并行 **:一段时间内同时一起执行多个任务(任务数量小于或等于CPU核心数)
  • 进程:资源分配的最小单位,操作系统进行资源分配和调度运行的基本单位,一个正在运行的程序就是一个进程

进程的创建步骤

1 导入进程包:import multiprocessing

2 通过进程类创建进程对象:进程对象 = multiprocessing.Process(target=任务名)

3 启动进程执行任务:进程对象.start()

import multiprocessing
import time
def coding():
    for i in range(3):
        print('coding...')
        time.sleep(0.2)
def music():
    for i in range(3):
        prin('music...')
        time.sleep(0.2)
        
if  __name__ == '__mian___':
    # 通过进程类创建对象
    coding_process = multiprocessing.Process(target=coding)
    music_process = multiprocessing.Process(target=music)
    # 启动进程
    coding_process.start()
    music_process.start()

进程执行带参数的任务

参数名说明
args以元祖的方式执行任务传参
kwargs以字典的方式执行任务传参

进程执行带有参数的任务传参有两种方式:

1 元组方式传参 :元组方式传参一定要和参数的顺序保持一致

2 字典方式传参:字典方式传参字典中的key一定要和参数名保持一致

# 通过进程类创建对象(带参数)
coding_process = multiprocessing.Process(target=coding,args=(3,))
music_process = multiprocessing.Process(target=music,kwargs={"count",2})
# 启动进程
coding_process.start()
music_process.start()

获取进程编号

1 获取当前进程编号:getpid( )方法

2 获取当前父进程编号:getppid( )方法

import os
def work():
    print('work进程编号:',os.getpid())
    print('work父进程编号:',os.getppid())

注意:进程之间不共享全局变量

import multiprocessing
import time
my_lst = []		# 创建全局变量
def writedata():
    for i in range(3):
        my_list.append(i)
    print('write_date:',my_list)
def read_data():
    print('read_data:',my_list)
    
if __name__ == '__main__':
    # 创建进程
    write_processs = multiprocessing.Procss(target=write_data)
    read_process = multiprocessing.Process(target= read_data)
    # 启动进程
    write_process.start()
    time.sleep(1)
    read_process.start()

主进程与子进程的结束顺序

1 主进程会等待所有的子进程执行结束后再结束

2 设置守护主进程:主进程退出后子进程直接销毁,不在执行子进程中的代码,子进程对象.daemon = True

3 销毁子进程:主进程退出之前把所有的子进程直接销毁,子进程对象.terminate()

import multiprocessing
import time
def work():
    for i in range(10):
        print('子进程工作中:')
        
if __name__ == '__main__':
    # 创建进程
    work_processs = multiprocessing.Procss(target=work)
   
    work_process.daemon = True	 # 方法1:设置守护主进程
    
    wrork_process.start()
    time.sleep(1)
    
    work_process.termnate()		# 方法2:销毁子进程,主进程退出之前把所有的子进程直接销毁
    
    print('主进程执行完了!')

1.2 多线程基础

线程:程序执行的最小单位,一个进程中最少有一个线程来负责执行程序,同一个进程中的多个线程共享进程所拥有的全部资源

线程的创建步骤

1 导入线程模块:import thrading

2 通过线程类创建线程对象:线程对象 = threading.Thread(target=任务名)

3 启动进程执行任务:进程对象.start()

import threading
import time
def coding():
    for i in range(3):
        print('coding...')
        time.sleep(0.2)
def music():
    for i in range(3):
        prin('music...')
        time.sleep(0.2)
        
if  __name__ == '__mian___':
    # 通过线程类创建对象
    coding_thread = threading.Thread(target=coding)
    music_thread = threading.Thread(target=music)
    # 启动线程
    coding_thread.start()
    music_thread.start()

注意

1 线程执行带参数的任务,与进程相同

2 主线程会等待所有的子线程执行结束后主线程再结束,

  • 设置守护主线程:threading.Thread(target=work,daemon=True)
  • 销毁子线程:子线程对象.setDaemon(Ture)
if __name__ == '__main__':
    # 创建线程
    # 方法1:设置守护主线程
    work_thread = threading.Thread(target=work,daemn=Ture)
   
    # 启动线程
    work_thrad.setDeamon(Ture)		# 方法2:销毁子线程
    wrork_streads.start()
    
    time.sleep(1)
    print('主线程执行完了!')

3 线程之间执行是无序

  • 通过current_thread方法获取线程对象:current _thread = threading.current_thread()
  • 通过current_thread对象可以知道线程的相关信息(如线程创建的顺序):print(current_thread)

4 多个线程在同一个进程中,线程之间共享全局变量

5 多线程同时操作全局变量时,会导致数据出现错误,可以用线程同步(互斥锁)方式解决问题

互斥锁:对共享数据进行锁定,保证同一时刻只有一个线程去操作,多个线程同时抢互斥锁,没有抢到的线程需等待到其他线程释放之后再去抢这个锁

互斥锁的使用:

1 互斥锁的创建:mutex = threading.Lock()

2 上锁:mutex.acquire()

3 释放锁:mutex.release()

import threading
g_num = 0

def sum_num1():
    mutex.acquire()		# 上锁
    for i in range(10000):
        global g_num
        g_num += 1
    mutex.release()		# 解锁
    print('g_num1:',g_num)
    
def sum_num2():
    mutex.acquire()		# 上锁
    for i in range(10000):
        global g_num
        g_num += 1
    mutex.release()		# 解锁
    print('g_num2:',g_num)

if __name__ = "__main__":
    # 创建互斥锁
    mutex = threading.Lock()
    
    sum1_thread = threading.Thread(target=sum_num1)
    sum2_thread = threading.Thread(target=sum_num2)
    
    sum1_thread.start()
    sum2_thread.start()

死锁:一直等待对方释放锁的情景就是死锁

进程与线程的对比

1 线程是依附在进程里面的,没有进程就没有线程

2 一个进程默认提供一条线程,进程可以创建多个线程

3 进程之间不能共享全局变量,但是线程之间可以

4 进程是操作系统资源分配的基本单位,线程是CPU调度的基本单位

5 进程可以使用多核,但是资源开销大,线程相反

2 网络编程

2.1 网络编程基础

网络:实现资源共享和信息传递的虚拟平台

socket:程序键网络数据通信的工具

IP地址:网络设备上网使用的数字标签,能够标识网络中唯一的一台设备

IP地址分为IPv4和IPv6两类,IPv4是目前使用的ip地址,IPv6是未来使用的ip地址

命令名说明
ifconfig查看网卡信息
ping检查网络是否正常

端口:传输数据的通道,每一个端口都有一个对应的端口号,端口号有65536个

1 知名端口号:众所周知的端口号(0-1023),21端口号分配给FTP文件传输协议服务。25端口号分配给SMTP简单邮件传输协议服务,80端口号分配给HTTP服务

2 动态端口号:程序员开发应用程序使用的端口号(1024-65535)

3 运行一个程序默认会有一个端口号,退出程序时所占用的端口号会被释放

2.2 TCP介绍

TCP:传输控制协议,一种面向连接的、可靠的、基于字节流的传输通信协议

  • 面向连接:通信双方必须先建立好连接才能进行数据的传输,并且双方都会为此连接分配必要资源用来记录连接的状态和信息
  • 可靠传输:TCP采用发送应答机制、超时重传、错误校验、流量控制和阻塞管理

数据的编码转化

  • encode:编码,将字符串转化为字节码,str.encode(encoding=“utf-8”)
  • decode:编码,将字节码转化为字符串,bytes.encode(encoding=“utf-8”)

TCP客户端程序开发

基本步骤:创建客户端套接字对象(买电话)——和服务端套接字建立连接(打电话)——发送数据(说话)——接收数据(接听)——关闭客户端套接字(挂电话)

在这里插入图片描述

客户端程序开发步骤:

  • 导入socket模块(import socket)——创建客户端socket对象是用socket类(socket.socket(AddressFamily,Type)
  • AddressFamily指代的是IP地址类型,Type指代的是传输协议类型
  • connect(和服务端套接字建立连接)、send(发送数据)、recv(接收数据)、close(关闭连接)
import socket

if __name__ == '__main__':
    # 1 创建客户端套接字对象
    tcp_client_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    # 2 和服务端套接字建立连接
    tcp_client_socket.connect(("192.168.81.283",8080))	# 此处输入要连接的ip地址
    # 3 发送数据
    tcp_client_socket.send("nihao".encode(encoding="utf-8"))
    # 4 接收数 recv 阻塞等待数据的到来
    rec_data = tcp_client_socket.recv(1024)
    print(recv_data.decode())
    # 5 关闭客户端套接字
    tcp_client_socket.close()

TCP服务端程序开发

基本步骤:创建服务端端套接字对象——绑定IP地址和端口号——设置监听——等待接受客户端的连接请求
——接收数据——发送数据——关闭套接字

服务端程序开发步骤:

  • 导入socket模块(import socket)——创建客户端socket对象是用socket类(socket.socket(AddressFamily,Type)
  • AddressFamily指代的是IP地址类型,Type指代的是传输协议类型
  • bind(绑定IP地址和端口号)、listen(设置监听)、accept(等待客户的连接请求)、recv(接收数据)、close(关闭连接)
import socket

if __name__ == '__main__':
    # 1 创建服务端套接字对象
    tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    # 设置端口复用,放置误认为端口号占用
    tcp_sercer_socket = socket.socket(socket.SOL_SOCKET,socket.SO_REUSEADDR,True)
    # 2 绑定IP地址和端口号
    # tcp_server_socket.bind(("192.168.81.283",8888))
    tcp_server_socket.bind(("",8888))	# 第一个元素为空,默认本机IP地址
    # 3 设置监听 128:代表服务端等待排队链接的最大数量
    tcp_server_socket.listen(128)	# 第一个元素为空,默认本机IP地址
    # 4 等待客户端的连接请求 accept阻塞等待 返回一个用以和客户端通信的socket,客户端的地址
    conn_socket,ip_port = tcp_server_socket.accept()
    print('客户端地址:',ip_port)
    # 5 接收数 recv 阻塞等待数据的到来
    rec_data = conn_socket.recv(1024)
    print('接受的数据:',recv_data.decode())
    # 6 发送数据
    conn_socket.send("客户端,你的数据我收到了".encode(encoding="utf-8"))
    # 7 关闭套接字
    conn_socket.close()
    tcp_server_socket.close()

注意:

1 send:发数据必须得通过网卡发送数据,应用程序是无法直接通过网卡发送数据的,它需要调用操作系统接口,也就是说,应用程序把发送的数据先写入到发送缓冲区(内存中的一片空间),再由操作系统控制网卡把发送缓冲区的数据发送给服务端网卡

2 recv:应用软件是无法直接通过网卡接收数据的,它需要调用操作系统接口,由操作系统通过网卡接收数据,把接收的数据写入到接收缓冲区(内存中的一片空间),应用程序再从接收缓存区获取客户端发送的数据

在这里插入图片描述

3 服务端服务多个客户端:listen之后加上while true循环,但是注意不要关闭服务端tcp_server_socket

while True:
    # 4 等待客户端的连接请求 accept阻塞等待 返回一个用以和客户端通信的socket,客户端的地址
    conn_socket,ip_port = tcp_server_socket.accept()
    print('客户端地址:',ip_port)
    # 5 接收数 recv 阻塞等待数据的到来
    rec_data = conn_socket.recv(1024)
    print('接受的数据:',recv_data.decode())
    # 6 发送数据
    conn_socket.send("客户端,你的数据我收到了".encode(encoding="utf-8"))
    # 7 关闭套接字
    conn_socket.close()
tcp_server_socket.close()

4 服务端同时服务多个客户端:当客户端和服务端建立连接成功,创建子线程,使用子线程专门处理客户端的请求,防止主线程阻塞

在这里插入图片描述

import socket
import threading

# 处理客户端函数
def handle_client(conn_socket):
    # 5 接收数 recv 阻塞等待数据的到来
        rec_data = conn_socket.recv(1024)
        print('接受的数据:',recv_data.decode())
        # 6 发送数据
        conn_socket.send("客户端,你的数据我收到了".encode(encoding="utf-8"))
        # 7 关闭套接字
        conn_socket.close()

if __name__ == '__main__':
    # 1 创建服务端套接字对象
    tcp_server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    # 设置端口复用,放置误认为端口号占用
    tcp_sercer_socket = socket.socket(socket.SOL_SOCKET,socket.SO_REUSEADDR,True)
    # 2 绑定IP地址和端口号
    # tcp_server_socket.bind(("192.168.81.283",8888))
    tcp_server_socket.bind(("",8888))	# 第一个元素为空,默认本机IP地址
    # 3 设置监听 128:代表服务端等待排队链接的最大数量
    tcp_server_socket.listen(128)	# 第一个元素为空,默认本机IP地址
    
    while True:
    	# 4 等待客户端的连接请求 accept阻塞等待 返回一个用以和客户端通信的socket,客户端的地址
        conn_socket,ip_port = tcp_server_socket.accept()
        print('客户端地址:',ip_port)
        
        # 使用多线程去接收多个客户的请求
        sub_thread = threding.Thread(target=handle_client,args=(conn_socket),)	# 注意需要将参数传入处理客户端函数
        sub_thread.start()
        
    tcp_server_socket.close()

2.3 HTTP协议

网址:URL,统一资源定位符(协议+域名+资源路径+可选参数)

在这里插入图片描述

域名:IP地址的别名,它是用点进行分割使用英文字母和数字组成的名字,使用域名目的就是方便的记住某台主机IP地址

在这里插入图片描述

参数说明:?后面page表示第一个参数,后面的参数都是用 & 进行连接

http协议:超文本传输协议,规定浏览器和web服务器之间通讯的数据格式

  • 超文本是指在文本数据的基础上还包括非文本数据,而这些非文本数据会使用链接的方式进行加载显示(超文本就是带有链接的文本数据,也就是我们常说的网页数据)
  • 传输HTTP协议格式的数据是基于TCP传输协议的,发送数据之前需要先建立连接。TCP传输协议是用来保证网络中传输的数据的安全性的,HTTP协议是用来规定这些数据的具体格式的

浏览器访问web服务器的过程

在这里插入图片描述

HTTP请求报文(分为GET和POST两种格式)

GET:获取Web服务器的数据,请求行+请求头+空行

在这里插入图片描述

POST:向Web服务器提交数据,请求行+请求头+空行+请求体

在这里插入图片描述

HTTP响应报文:请求行+请求头+空行+请求体

在这里插入图片描述

状态码:表示Web服务器响应状态的3为数字代码

状态码说明
200服务器已经成功处理了请求
400错误的请求,请求地址或者参数错误
404请求资源在服务器不存在
500服务器内部源代码出现问题

HTTP协议的通讯过程
在这里插入图片描述

标签:__,socket,Python,编程,tcp,线程,进程,多任务,客户端
From: https://blog.csdn.net/RunningJie/article/details/140565643

相关文章

  • 尖刺花朵 彩 Python
    importturtleasts=133t.speed(0)qa=0h=['red','yellow','green','black','pink','orange','brown']foriinrange(99999999999999999999999):  t.fillcolor(h[s%7])  ifi%3==2:   ......
  • python-最小公倍数(PythonTip)
    [题目描述]编写一个程序,找出能被从1到给定数字n(包括n)的所有数字整除的最小正数(即最小公倍数)。定义函数smallest_multiple()的函数,参数为n。在函数内,返回能被从1到给定数字n(包括n)的所有数字整除而无余数的最小正数。示例输入:5示例输出:60比如,对于输入5,最小公倍数是60,因为......
  • Python和pycharm的环境安装
    1.Python的安装方法一、Python的官网下载地址:https://www.python.org/downloads/   下载安装方法二、anaconda安装(开源的Python发行版本)下载版本列表:https://repo.anaconda.com/archive/重要说明:如果你下载最近版本安装的过程中出现:failedtoextractpackages弹窗提......
  • 在终端怎么升级python
    对于Windows系统:打开命令行终端:使用快捷键"Win+R"打开运行窗口,输入"cmd"并按下"Enter"键。安装或更新pip(如果尚未安装):输入命令python-mensurepip--upgrade来安装或更新pip。升级Python:注意:直接通过pip升级Python可能并不总是可行的,因为pip主要用于管理Python包,而不是Pyt......
  • python内置zip函数详解
          在Python中,zip是一个内置函数(其实是一个class),可以将多个可迭代对象(如列表、元组等)作为参数,将对象中对应index的元素打包成一个个的元组,然后返回由这些元组tuple组成的zip迭代器(之前文章讲过,类中包含了__iter__和__next__魔法方法可作为迭代器)。以下是pytho......
  • 将Json格式的文件转为Excel格式文件的python代码
    importpandasaspdimportosfromopenpyxlimportWorkbook'''pandas是Python中用于数据分析的一个非常强大的库,它提供了快速、灵活和表达式丰富的数据结构,旨在使“关系”或“标签”数据的处理工作变得既简单又直观。pandas非常适合于处理表格数据,如CSV文件、SQL查询结......
  • Python正则表达式
    文章目录了解元字符常用的元字符正则表达式进阶re模块match方法切分字符串分组贪婪匹配预编译字符串是编程时涉及到的最多的一种数据结构,对字符串进行操作的需求几乎无处不在。比如判断一个字符串是否是合法的Email地址,虽然可以编程提取@前后的子串,再分别判断是否是单......
  • Python进阶(4)--正则表达式
    正则表达式在Python中,正则表达式(RegularExpression,简称Regex)是一种强大的文本处理工具,它允许你使用一种特殊的语法来匹配、查找、替换字符串中的文本。在这之前,还记得之前我们是通过什么方法分割字符串的嘛?strs="a,b;c@d"print(strs.split(",")) #以“,”为分割点分割......
  • 0基础学python-18:掌管匹配机制的模块——re
    目录前言使用正则表达式的背景: 元字符 匹配的范围 正则表达式1.importre2.re.match(r"匹配的规则",所要匹配的字符串) 3.匹配一个变量名 4.转义字符的匹配5.分组匹配6.贪婪匹配7.预编译前言        正则表达式(RegularExpression,简称regex或......
  • C#/.NET这些实用的编程技巧你都会了吗?
    DotNetExercises介绍DotNetGuide专栏C#/.NET/.NETCore编程常用语法、算法、技巧、中间件、类库练习集,配套详细的文章教程讲解,助你快速掌握C#/.NET/.NETCore各种编程常用语法、算法、技巧、中间件、类库等等。GitHub开源地址:https://github.com/YSGStudyHards/DotNetExercise......