Python进阶 网络编程笔记-多进程

Python 进阶 网络编程与多进程


一、网络编程在解决什么问题

网络 :很多台电脑用网线、WiFi、路由器等连在一起,按共同遵守的规则(协议)交换数据。

网络编程 :写程序让运行在不同电脑上的两个进程 之间能发数据、收数据

比喻:

  • IP 地址 :小区地址------确定是哪一栋楼(哪一台设备)
  • 端口号 :门牌 / 窗口号------同一栋楼里有很多房间(很多程序),端口决定数据交给哪一个程序
  • 协议 :两个人都说普通话------约定数据怎么打包、怎么确认、怎么重传,双方对得上才能通信。

一句话:IP 找机器,端口找程序,协议定规矩。


二、IP 地址与端口

IP 地址 :在网络里大致唯一标识一台设备 。同一局域网里常用形如 192.168.x.x 的形式;本机自己和自己测可以用 127.0.0.1(回环地址)。

端口 / 端口号 :一台电脑上可以同时跑浏览器、微信、你写的 Python 程序。只凭 IP 只能找到电脑,端口用来区分"这份数据交给哪个进程" 。端口一般是 0~65535 的整数,写程序时常用 1024 以上的端口,避免和系统常用服务冲突。公有端口1-1023 动态端口:1024-65535

本机小操作(Windows)

在命令行用 ipconfig 可以看本机 IP;用 ping 某 IP 或域名 可以粗测网络通不通;ping 127.0.0.1 测本机协议栈是否正常。


三、TCP 协议

1. TCP 的三大特点

  1. 面向连接

    真正传业务数据之前,必须先建立连接(底层就是你下面要学的三次握手)。就像打电话要先拨通再说话,不是丢完就走。

  2. 可靠传输

    有确认、重传、按序等机制,尽量保证:你发过去的字节流,对方按顺序收到(或发现错误、连接异常)。适合文件、网页、聊天等"不能乱、不能大面积丢"的场景。

  3. 面向字节流

    传送的是连续的字节流,没有"消息边界"帮你分包,应用层要自己约定"一条命令到哪算结束"(例如换行、固定长度、先长度再内容等)。

UDP 对比帮助记忆(本课代码以 TCP 为主):UDP 无连接 、不保证可靠、发出去就不管,像发短信;TCP 像打电话,更"啰嗦"但更稳。


2. 三次握手:建立连接时到底发生了什么

三次握手指的是:客户端和服务器之间连续交换三个带控制位的报文段 ,把"我要连你""我准备好了""我也准备好了"说清楚,并交换初始序号,后面的可靠传输都依赖这些序号。

可以按下面四列来记:谁发起、发什么、对方收到后明白什么、这一步的意义

次序 方向 发送内容(习惯说法) 含义(白话)
第 1 次 客户端 → 服务器 SYN "我想建立连接,这是我的初始序号(seq)。"
第 2 次 服务器 → 客户端 SYN + ACK "我收到了你的请求(ACK),我也发起我这一侧的连接(SYN),这是我的初始序号。"
第 3 次 客户端 → 服务器 ACK "我收到了你的 SYN,双方序号对齐,可以开始传数据。"

这一阶段你要抓住的重点:

  1. 为什么是"三次"而不是两次?

    两次只能保证"一方知道另一方在线",没法可靠地统一双方的初始序号、也没法很好地处理旧的、重复的连接请求 。三次是在工程上公认的最小可用 做法:既让双方都确认"对方愿意连、自己也愿意连",又把两边的起始序号对齐,避免很多边角问题。面试时可以说:防止历史连接请求的报文扰乱本次连接、并同步双方初始序列号

  2. 握手阶段还几乎不传业务数据 ,主要是同步状态 。真正 send 的业务数据是在握手完成之后。

  3. SYN 洪泛等攻击和 SYN 报文有关,了解即可;写应用时知道"连上之前必经历这三步"即可。

  4. 作用: 确认双方的发送与接收能力正常


3. 四次挥手:关闭连接时为什么往往是四步

TCP 是全双工 :同一时间里,A 可以给 B 发,B 也可以给 A 发,两个方向可以独立关闭

关闭时常见情况是:一边先说自己"发完了" ,另一边可能还有数据没发完,所以要分步确认,不能像握手那样简单合并成三步。

次序 方向 发送内容(习惯说法) 含义(白话)
第 1 次 主动关闭方 → 被动方 FIN "我这边的数据发完了,我要关闭我这边的发送。"
第 2 次 被动方 → 主动关闭方 ACK "我知道你发 FIN 了。"此时被动方还可以继续发数据给主动方。
第 3 次 被动方 → 主动关闭方 FIN "我这边也发完了,我也关闭发送。"
第 4 次 主动关闭方 → 被动方 ACK "我知道你 FIN 了。"连接完全释放过程中还要处理最后的确认。

这一阶段你要抓住的重点:

  1. 为什么是四次?

    被动方收到对方的 FIN 时,往往立刻回 ACK 表示"我知道你关了",但自己可能还没发完数据 ,所以要等自己这边也发完 ,再单独发自己的 FIN。因此中间的 ACK 和最后的 FIN 通常不能合二为一,就形成了四次挥手(少数情况下第二步和第三步可以合并成"带 FIN 的 ACK",那是特例)。

  2. 全双工:关的是"某一个方向上的发送/接收",不是一瞬间两个方向同时无声无息消失。

  3. 主动关连接的一方 在发完最后一个 ACK 之后会进入 TIME_WAIT 状态有一段时间------为了万一最后一个 ACK 丢了,对方重传 FIN 时你还能补 ACK。初学知道"用来兜底丢包"即可。


四、Socket 是什么

Socket(套接字)是操作系统提供给你的编程接口 :你的 Python 程序通过它,把"发网络数据、收网络数据"这些底层细节包装成几个函数调用

  • 你用 socket.socket(地址族, 类型) 创建一个套接字对象。
  • IPv4 + TCP 对应:socket.AF_INETsocket.SOCK_STREAM

可以理解为:有了一个能走 TCP、能选 IPv4 地址的通信端点


五、TCP 编程整体流程:服务端在做什么、客户端在做什么

先记角色

  • 服务端 :在自家电脑上开好端口等人连(被动)。
  • 客户端知道对方的 IP 和端口,主动连过去(主动)。

下面按推荐顺序把每一步讲清楚(这是你必须能默画、能讲给别人听的)。


(一)服务端:从"建套接字"到"能和一个人聊天"

步骤 函数 这一步在干什么(必须能口述)
1 socket.socket(AF_INET, SOCK_STREAM) 向系统申请一个 TCP / IPv4 套接字。还没有绑定到具体 IP 和端口。
2 bind((IP, 端口)) 声明:我这个程序在这个 IP 的这个端口上"安家" 。别人要连服务器,就连这个地址。''0.0.0.0 常表示监听本机所有网卡127.0.0.1 只有本机程序能连。参数必须是二元组 ,端口是整数
3 listen(backlog) 把套接字设为被动监听 状态:backlog 表示排队等待你 accept 的连接 最多能堆多少。之后才能在这一步的套接字上 accept
4 accept() 阻塞 :直到有一个客户端完成三次握手连上来。返回 (新套接字, 客户端地址)关键 :从此刻起你有两个套接字角色 ------原来的 继续负责"在门口接人";新的 专门和当前这位客户端收发数据。
5 新套接字.recv(大小) 当前连接 收最多这么长的字节,返回 bytes阻塞 直到收到数据或连接关闭。要对 accept 返回的那只套接字操作 (常写成 conn.recv),不要对监听套接字 recv
6 新套接字.send(字节数据) 往当前连接发数据;Python 3 里要发字符串需先 .encode('utf-8')。同样用 accept 返回的那只套接字 (如 conn.send)。
7 新套接字.close() 结束和这一位客户端的会话(底层会走关闭流程)。
(可选) 原监听套接字.close() 若服务器程序要彻底退出、不再接任何客户,再关监听套接字。很多练习里为了继续接下一单,不关监听套接字。

口诀(帮助背顺序) :创建 → 绑定 → 监听 → 接电话(accept)听/说(recv/send) → 挂机(close)。


(二)客户端:从"建套接字"到"连上服务器"

步骤 函数 这一步在干什么
1 socket.socket(AF_INET, SOCK_STREAM) 同样创建一个 TCP / IPv4 套接字。
2 connect((服务器IP, 端口)) 主动 向对方的 bind 地址发起连接;底层完成三次握手 。成功后才算"线路通了"。通常会阻塞到连上或失败。
3 send / recv 和服务端一样,用这同一个套接字收发(客户端没有"接听套接字"和"通话套接字"的拆分)。
4 close() 关闭连接。

(三)小结:服务端与客户端"长得不一样"的地方

  • 服务端多 bindlistenaccept ;客户端用 connect 代替这三步里的"等人连"逻辑。
  • 服务端 accept 会多出一个新套接字 ;客户端始终就一个套接字在和服务器说话。
  • acceptconnectrecv 常常阻塞:程序会停在这一行,直到连上、直到收到数据,或连接异常------写多任务时就会明白为什么要进程/线程。

六、字符串与二进制(encode / decode)

网络里传的是 字节(bytes) ,不是 Python 里的 str

  • 发送:"你好".encode('utf-8')
  • 接收:data.decode('utf-8')

双方必须用同一种编码 ,否则就会乱码。多数项目默认 UTF-8


七、端口被占用:端口重用

现象:服务器刚关,立刻再运行,提示地址已被占用(和 TIME_WAIT 等有关)。

做法:在 bind 之前调用:

python 复制代码
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)

记住:一定要在 bind,否则起不到你想要的"立刻重启还能绑同一端口"的效果。


八、循环 accept:一个接一个接待多个客户端

text 复制代码
while True:
    新套接字, 地址 = 监听套接字.accept()
    # 用 新套接字 recv / send
    新套接字.close()

含义:可以一个接一个地服务很多客户 ,但同一时刻通常只有一个循环在执行 ,若你在内层又用 while 跟一个人聊很久,别人还是要等 ------这就是"单线程顺序服务"。要很多人同时 传文件、同时聊天,后面要用多进程、多线程或异步 ,本课会先用多进程做入门。


九、文件上传思路(和聊天同一套 API)

  • 服务器accept 后用 wb 打开要保存的文件;循环 recv(一块大小) ,把收到的 bytes write 进文件;若 recv 得到空字节 b'' (长度为 0),一般表示对方关连接了,上传结束,跳出循环。
  • 客户端rb 读本地文件,循环 send 一块 ;发完 close()

为什么要分块? 文件可能很大,一次读进内存不现实;网络也是流式的,适合边读边发、边收边写。


十、多任务:并发和并行

并发 :一段时间内多个任务在交替执行 (单核 CPU 快速切换,看起来像同时)。

并行多核 时,不同任务真的在同一时刻各跑各的核心

多任务的目的:让 CPU 别闲着 ,提高整体效率。

和后面线程对比时先记一句:进程之间数据默认不共享;同进程里的线程共享内存(以后会细讲锁)。


十一、多进程:multiprocessing

进程:程序的一次运行实例;操作系统给进程分配资源(内存空间等)。打开一个软件,通常至少一个进程。

1. 创建与启动

python 复制代码
import multiprocessing

def job():
    print("子进程里的代码")

if __name__ == '__main__':
    p = multiprocessing.Process(target=job)
    p.start()
  • target=函数名 ,不要写成 job()(加了括号就变成"先执行函数再把返回值当 target"了)。
  • start() 才真正启动子进程。

Windows 必记 :创建进程、写 Processstart() 的代码要放在

python 复制代码
if __name__ == '__main__':

里面,否则可能反复启动子进程或报错。

2. 传参:argskwargs

python 复制代码
def work(name, n):
    ...

p1 = multiprocessing.Process(target=work, args=('张三', 5))
p2 = multiprocessing.Process(target=work, kwargs={'name': '李四', 'n': 10})
  • args :元组,按位置传。只有一个参数时要写成 (x,) ,不能写成 (x),后者在 Python 里不是元组。
  • kwargs:字典,键名必须和函数参数名一致。

3. 查看 PID

python 复制代码
import os
import multiprocessing

os.getpid()                      # 当前进程号
os.getppid()                     # 父进程号
multiprocessing.current_process().pid

进程结束后 PID 会被系统回收,以后可能被别的进程复用;在存活期内可以把它当成该进程的标志。

4. 全局变量为什么不共享

每个子进程里是父进程内存的一份拷贝 ,模块级别的 my_list = []不同进程里各有一份 。一个进程里 append,另一个进程看不到 。要在进程间传数据,需要队列、Manager、管道等(后面课程会接触);先建立"默认不共享"的直觉

5. 守护进程 daemon

python 复制代码
p = multiprocessing.Process(target=job)
p.daemon = True   # 要在 start() 之前设
p.start()

守护进程主进程退出 而结束,适合"主程序关了,后台辅助任务也不用留了"的场景;默认则主进程会等子进程跑完再结束(行为因写法略有差异,以课堂演示为准)。


十二、容易写错的地方

  1. bind 写成 bind('127.0.0.1', 8080)------少了括号,应该是 bind(('127.0.0.1', 8080))
  2. 端口写成字符串 '8080'------应该是 整数 8080
  3. 监听套接字recv / send------应对 accept 返回的套接字操作。
  4. 忘了 encode / decode,或两端编码不一致。
  5. SO_REUSEADDR 写在 bind 后面
  6. recv 得到 b'' 仍死循环------要判断长度为 0 表示对端关了。
  7. Windows 下 if __name__ == '__main__': 忘写。
  8. args=(5) 不是单元素元组,应 args=(5,)

今日自测

1. IP 地址的作用

在网络中唯一标识一台设备 ,让数据能到达"哪台电脑"。可记:收货地址、楼栋

2. 端口号的作用

在一台计算机上**标识正在运行的哪个程序(进程)**接收数据。

IP 找机器,端口找程序。

3. TCP 的特点

面向连接可靠传输面向字节流。(可与 UDP 对比记忆。)

4. TCP 服务器端收发消息要走哪些步骤?

socket 创建 → bindlistenaccept 得到新套接字recv / send(在新套接字上)close 新套接字;监听套接字可继续接人。

5. 什么是进程?

程序在操作系统里的一次运行实例,是资源分配的基本单位。

6. 怎么用 multiprocessing 起多进程?

import multiprocessing obj = multiprocessing.Process(target=函数名, args=..., kwargs=...)obj.start() ;Windows 下代码放在 if __name__ == '__main__':

7. 怎么获取 PID?

os.getpid()os.getppid()multiprocessing.current_process().pid

8. argskwargs 怎么用?

args 元组按位置传,单元素写 (x,)kwargs 字典按关键字传,键对齐参数名。

9. 进程之间共享全局变量吗?

默认不共享;各进程有独立拷贝,要共享需专门机制。


最小示例

服务端(单次接一个客户端、收一条再回一条):

python 复制代码
import socket

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
server.bind(('0.0.0.0', 9000))
server.listen(128)

conn, addr = server.accept()
data = conn.recv(1024).decode('utf-8')
print("收到:", data)
conn.send("服务器已收到".encode('utf-8'))
conn.close()
server.close()

客户端:

python 复制代码
import socket

c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
c.connect(('127.0.0.1', 9000))
c.send("你好".encode('utf-8'))
print(c.recv(1024).decode('utf-8'))
c.close()

先按注释理解顺序,再改成你自己的 IP 和端口做练习。

相关推荐
chnyi6_ya1 小时前
论文阅读笔记|Wan: Open and Advanced Large-Scale Video Generative Models
论文阅读·笔记
sheeta19981 小时前
LeetCode 每日一题笔记 日期:2026.05.31 题目:2126. 摧毁小行星
笔记·算法·leetcode
AwakeFantasy1 小时前
量化系统难题1_复权后的日k数据_已解决
python·金融
jay神1 小时前
基于 Python + Flask + Vue 的校内求职互助平台
前端·vue.js·后端·python·flask·毕业设计
weixin_468466851 小时前
Cherry-Studio 新手极速上手指南
人工智能·python·深度学习·ai·自然语言处理·大模型
有个人神神叨叨1 小时前
Agent 记忆学习笔记-1.1
笔记·学习
三块可乐两块冰1 小时前
rag笔记4
笔记
问心无愧05131 小时前
ctf show web入门58
前端·笔记
AwakeFantasy1 小时前
聊聊近况和最近做的踩坑项目
人工智能·python·gpt·ocr