网络编程介绍

  • 概述

    就是用来实现网络互联的 不同计算机上 运行的程序间 可以进行数据交互.

  • 三要素

    • IP地址: 设备(电脑, 手机, Ipad…)在网络中的唯一标识

      分类:

      ​ IPV4, 4字节, 十进制. 例如: 192.168.88.100

      ​ IPV6, 8字节, 十六进制, 宣传语: 可以让地球上的每一粒沙子都有自己的IP

      两个DOS命令:

      ​ 查看IP:

      ​ windows: ipconfig

      ​ Linux, Mac: ifconfig

      ​ 测试网络连接:

      ​ ping ip地址 或者 域名

    • 端口号: 程序在设备(电脑, 手机, Ipad…)上的唯一标识.

      范围: 0 ~ 65535, 其中0 ~ 1023已经被系统占用或者用作保留端口, 自定义端口时尽量规避这个范围.

    • 协议: 传输规则, 规范.

      常用的协议:

      ​ TCP(这个用的最多) 和 UDP

      TCP特点:

      ​ 1.面向有连接

      ​ 2.采用字节流传输数据, 理论无大小限制.

      ​ 3.安全(可靠)协议.

      ​ 4.效率相对较低.

      ​ 5.区分客户端和服务器端.

入门创建Socket对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
"""
网络编程介绍:
概述:
网络编程也叫网络同学,socket通信。即通信双方都有自己的socket对象
大白话:
你和你遥远的朋友在聊天的时候,看似你们两个在交互,其实通过手机(双方手机)来交互
"""

#1.导包
import socket

#2.创建对象
# AddressFamily :地址族 即 IPV4 还是用IPV6 默认AF_INET(IPV4) AF_INET6(IPV6)
# socket type :socket类型 即 TCP 还是 UDP 默认SOCK_STREAM (TCP) SOCK_DGRAM(UDP)
cr_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM) # IPV4 和 TCP
print(cr_socket)

网编案例_一句话交情

  • 图解

    1742178741721

  • 服务器端代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    """
    案例:网络编程入门 服务器给客户端发送消息,客户端给服务器回执信息
    1. 创建服务端套接字对象
    2. 绑定端口号
    3. 设置监听
    4. 等待接受客户端的连接请求
    5. 发送数据
    6. 接收数据
    7. 关闭套接字

    细节:客户端和服务器都是流程 字节流的形式实现的
    """
    # 0.导包
    import socket

    # 1. 创建服务端套接字对象
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2. 绑定端口号 已元组形式进行传递数据ip 和端口号
    server_socket.bind(('127.0.0.1', 8888))
    # 3. 设置监听
    server_socket.listen(5)
    # 4. 等待接受客户端的连接请求 (拆包)
    accept_socket, client_info = server_socket.accept()
    # 5. 发送数据 b是把数据转换为二进制(字母、数字、特殊符号)
    accept_socket.send(b"welcome to socket")
    # 6. 接收数据
    data = accept_socket.recv(1024).decode("utf-8")
    print(f"服务器端收到来自{client_info}的信息:{data}")
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
    # 7. 关闭套接字
    accept_socket.close()
    # server_socket.close() #服务器端一般不关闭

  • 客户端代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    """
    TCP客户端操作步骤流程:
    1. 创建客户端套接字对象
    2. 客户端连接服务器端
    3. 接收数据
    4. 发送数据
    5. 关闭套接字
    """
    import socket
    # 1. 创建客户端套接字对象
    clinet_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2. 客户端连接服务器端
    clinet_socket.connect(("127.0.0.1", 8888))
    # 3. 接收数据
    data = clinet_socket.recv(1024).decode("utf-8")
    print(f"客户端收到:{data}")
    # 4. 发送数据
    clinet_socket.send("socket很好玩,很有趣,我很喜欢!".encode("utf-8"))
    # 5. 关闭套接字
    clinet_socket.close()

网编案例_模拟多任务服务器端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
"""
案例:网络编程入门 服务器给客户端发送消息,客户端给服务器回执信息
1. 创建服务端套接字对象
2. 绑定端口号
3. 设置监听
4. 等待接受客户端的连接请求
5. 发送数据
6. 接收数据
7. 关闭套接字

细节:客户端和服务器都是流程 字节流的形式实现的
循环实现接受多个客户端消息
"""
# 0.导包
import socket

# 1. 创建服务端套接字对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2. 绑定端口号 已元组形式进行传递数据ip 和端口号
server_socket.bind(('192.168.13.62', 8888))
# 3. 设置监听
server_socket.listen(5)
# 4. 等待接受客户端的连接请求 (拆包)
while True:
try:
accept_socket, client_info = server_socket.accept()
# 5. 发送数据 b是把数据转换为二进制(字母、数字、特殊符号)
accept_socket.send(b"welcome to socket")
# 6. 接收数据
data = accept_socket.recv(1024).decode("utf-8")
print(f"服务器端收到来自{client_info}的信息:{data}")
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 7. 关闭套接字
accept_socket.close()
# server_socket.close() #服务器端一般不关闭
except:
pass

扩展_编解码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
"""
细节:
编码 : 把我们看的懂得 转成 我们看不懂的
'字符串'.encode(码表)
解码: 把我们看不懂的 转成 我们看得懂
二进制.decode(码表)
乱码:编解码格式不一致
二进制数据的特殊写法:即 b 字母、数字、特殊符号
"""

s1 = '黑马1234abc!'
# 编码
print(s1.encode())
print(s1.encode("utf-8"))
# 结论 当没有指定码表的时候默认就是 utf-8

# 解码
s2 = b'\xe9\xbb\x91\xe9\xa9\xac1234abc!'
print(type(s2))
print(s2.decode()) # 默认解码格式utf-8

s4="黑马"
sgbk = s4.encode("gbk")
print(sgbk)
print(sgbk.decode("utf-8"))

网编案例_文件上传

  • 图解

    1742186023575

  • 服务器端代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    """
    1:创建socket对象
    2:绑定ip、端口号
    3:设置最大监听数
    4:等待客户端申请连接
    5:读取客户端上传的文件数据,写入到目的文件
    6:释放资源
    """
    import socket

    # 1:创建socket对象
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2:绑定ip、端口号
    server_socket.bind(("127.0.0.1", 9999))
    # 3:设置最大监听数
    server_socket.listen(10)
    # 4:等待客户端申请连接
    accept_socket, clien_info = server_socket.accept()
    # 5:读取客户端上传的文件数据,写入到目的文件
    with open("./data/my.txt", "wb") as dats_f:
    # 5.1循环读取
    while True:
    # 5.2接受客户端上传数据
    data_bys = accept_socket.recv(1024)
    if len(data_bys) == 0:
    break
    dats_f.write(data_bys)
    # 6:释放资源
    accept_socket.send("文件上传成功!".encode("utf-8"))
    accept_socket.close()

  • 客户端

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    """
    1:创建客户端socket对象
    2:连接服务器端 ip 和端口
    3:关联数据源文件 读取内容 ,写给服务器端
    4:释放资源
    """
    import socket
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client_socket.connect(("127.0.0.1", 9999))
    # 3:关联数据源文件 读取内容 ,写给服务器端
    with open("d:/绕口令.txt", "rb") as src_f:
    while True:
    data = src_f.read(1024)
    # 发送给服务器端
    client_socket.send(data)
    if len(data) == 0:
    break
    print("客户端收到消息")
    client_socket.close()

扩展_模拟多任务版文件上传服务器端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
"""
1:创建socket对象
2:绑定ip、端口号
3:设置最大监听数
4:等待客户端申请连接
5:读取客户端上传的文件数据,写入到目的文件
6:释放资源
"""
import socket

# 1:创建socket对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2:绑定ip、端口号
server_socket.bind(("192.168.13.62", 9999))
# 3:设置最大监听数
server_socket.listen(10)
count = 0
while True:
count+=1
try:
# 4:等待客户端申请连接
accept_socket, clien_info = server_socket.accept()
# 5:读取客户端上传的文件数据,写入到目的文件
with open("./data/picture_"+str(count)+'.jpg', "wb") as dats_f:
# 5.1循环读取
while True:
# 5.2接受客户端上传数据
data_bys = accept_socket.recv(3072)
if len(data_bys) == 0:
break
dats_f.write(data_bys)
# 6:释放资源
accept_socket.send("文件上传成功!".encode("utf-8"))
accept_socket.close()
except:
pass

多任务简介

  • 概述

    让多个任务”同时”执行, 目的是: 充分利用CPU资源, 提高程序的执行效率.

  • 方式

    • 并发: 针对于单核CPU来讲, 多个任务同时请求执行时, CPU做高效切换即可.
    • 并行:针对于多核CPU来讲, 多个任务同时执行.
  • 图解

    1742195490886

单任务代码演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
"""
案例: 演示单任务, 前边不执行完毕, 后边绝对无法执行.
"""

# 1.定义函数A, 输出10次 hello world
def func_a():
for i in range(1000000):
print("hello world")

# 2. 定义函数B, 输出10次 hello python
def func_b():
for i in range(2):
print("hello python")


func_a()
print('-' * 23)
func_b()

多进程入门案例

  • 入门案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    """
    多进程实现步骤:
    1. 导入进程工具包
    import multiprocessing
    2. 通过进程类 实例化进程 对象
    子进程对象 = multiprocessing.Process()
    3. 启动进程执行任务
    进程对象.start()
    需求:使用多进程来模拟一边编写代码,一边听音乐功能实现。
    """
    # 1. 导入进程工具包
    import multiprocessing
    import time

    # 编写代码
    def coding():
    for i in range(1, 20):
    time.sleep(0.1)
    print(f"正在敲第{i}遍代码")
    # 听音乐
    def music():
    for i in range(1, 20):
    time.sleep(0.1)
    print(f"正在听第{i}遍音乐")

    if __name__ == '__main__':
    #单任务
    # music()
    # coding()

    # 2.通过进程类实例化进程对象
    p1 = multiprocessing.Process(target=coding)
    p2 = multiprocessing.Process(target=music)

    p1.start()
    p2.start()

  • 带参数的多进程代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    """
    使用多进程来模拟小明一边编写num行代码,一边听count首音乐功能实现。

    进程传参的方式有两种
    1:args方式 接受所有参数,以元组的方式 (位置参数)
    2:kwargs方式 接受所有参数,以字典的方式 (关键字参数)
    """
    # 1. 导入进程工具包
    import multiprocessing
    import time


    # 编写代码
    def coding(name,age):
    for i in range(1, 20):
    print(name, age,end="")
    time.sleep(0.1)
    print(f"正在敲第{i}遍代码")


    # 听音乐
    def music(name,age):
    for i in range(1, 20):
    print(name, age,end="")
    time.sleep(0.1)
    print(f"正在听第{i}遍音乐")


    if __name__ == '__main__':
    # 创建两个子进程 ,并且给进程传递参数
    p1 = multiprocessing.Process(target=coding, name="Process-1",args=('小明', 30))
    p2 = multiprocessing.Process(target=music, name="Process-2",kwargs={'name': '某只羊', "age": 33})
    p1.name


获取进程编号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
"""
进程编号解释:
概述:
在设备中,每个程序(进程)都有用自己的唯一的进程id,当程序释放的时候,该进程id也会释放,即
进程id可以重复使用
目的:
1:查看子进程的父进程 方便管理
2:例如杀死指定进程
格式:
方式一:os.getpid()的使用
方式二:import multiprocessing
pid = multiprocessing.current_process().pid

细节: main中创建进程,如果没有特殊指定,他的父进行都是main进程
而main进程的父进程,pycham程序是pid

"""
import os

"""
使用多进程来模拟小明一边编写num行代码,一边听count首音乐功能实现。

进程传参的方式有两种
1:args方式 接受所有参数,以元组的方式 (位置参数)
2:kwargs方式 接受所有参数,以字典的方式 (关键字参数)
"""
# 1. 导入进程工具包
import multiprocessing
import time

# 编写代码
def coding(name, age):
for i in range(1, 20):
print(name, age, end="")
time.sleep(1)
print(f"正在敲第{i}遍代码")
print(f"p1进程的pid{os.getpid()},{multiprocessing.current_process().pid},父进程id(ppid):{os.getppid()}")


# 听音乐
def music(name, age):
for i in range(1, 20):
print(name, age, end="")
time.sleep(1)
print(f"正在听第{i}遍音乐")
print(f"p2进程的pid{os.getpid()},{multiprocessing.current_process().pid},父进程id(ppid):{os.getppid()}")

if __name__ == '__main__':
# 创建两个子进程 ,并且给进程传递参数
p1 = multiprocessing.Process(target=coding, name="Process-1", args=('小明', 30))
p2 = multiprocessing.Process(target=music, name="Process-2", kwargs={'name': '某只羊', "age": 33})
p1.start()
p2.start()
# 查看主进程信息
print(f"main进程的pid{os.getpid()},{multiprocessing.current_process().pid},父进程id(ppid):{os.getppid()}")

进程特点_数据隔离

  • 图解

    1742899626719

  • 代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    """
    前置要求: (了解代码看懂现象)
    进程特点:
    1:进程之间的数据是相互隔离的。
    因为子进程相当于父进程的“副本”。会将父进行的main外资源拷贝一份。即:各是各的
    2:默认情况下,主进程会等待子进程执行结束再结束
    """
    import multiprocessing
    import time

    # 需求:在不同进程中修改列表my_list[]并新增元素,试着在各个进程中观察列表的最终结果

    # 1、定义一个公共的数据容器my_list[]
    my_list = []


    # 2、定义函数,向容器中添加数据
    def writer_data():
    for i in range(1, 6):
    my_list.append(i)
    print(f"添加数据:{i}")
    # print(f"writer_data函数{my_list}")
    # 定义函数 ,从容器中读取数据
    def read_data():
    time.sleep(3)
    print(f"read_data函数:{my_list}")


    if __name__ == '__main__':
    p1 = multiprocessing.Process(target=writer_data)
    p2 = multiprocessing.Process(target=read_data)

    p1.start()
    p2.start()

进程特点_守护进程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
"""
进程特点:
1:进程之间的数据是相互隔离的。
因为子进程相当于父进程的“副本”。会将父进行的main外资源拷贝一份。即:各是各的
2:默认情况下,主进程会等待子进程执行结束再结束
思路1:设置子进程为“守护”线程。
思路2:强制关闭子进程。可能会导致子进程变为僵尸进程。交由python解释器自动回收(底层有init初始化进程来进行严格管理)
"""
import multiprocessing
import time


def work():
for i in range(100):
print("我努力工作中.....")
time.sleep(0.2)


if __name__ == '__main__':
# p1进程
p1 = multiprocessing.Process(target=work)
# 设置守护进程 为p1设置守护进程
# p1.daemon = True

p1.start()

# 主进程(main)休眠1s后结束
time.sleep(1)
#思路2:强制关闭子进程
p1.terminate()
print("main进程结束了")

线程入门

  • 无参数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    """

    线程使用步骤
    1:导包
    2:创建线程对象
    3:启动线程

    线程和进程的关系
    1:进程是CPU分配资源的基本单位,线程是CPU调度资源的最小单位
    2:线程依附与进程的。每个进程至少有一个线程(主线程)
    3:进程间数据是相互隔离的。(同一个进程)线程间的数据是可以共享的
    """
    import threading, time


    # 编写代码
    def coding():
    for i in range(1, 200):
    time.sleep(0.1)
    print(f"正在敲第{i}遍代码")


    # 听音乐
    def music():
    for i in range(1, 200):
    time.sleep(0.1)
    print(f"正在听第{i}遍音乐")


    if __name__ == '__main__':
    t1 = threading.Thread(target=coding)
    t2 = threading.Thread(target=music)

    #这里 A

    t1.start()
    t2.start()

    #这里 B
    for i in range(1,20):
    time.sleep(0.1)
    print(f"main{i}")