🌙
交互式练习

LLM 练习 004

33 道题 · 选择题 + 填空题 + 简答题 + 代码实战 · 即时反馈 · 记录保存
← 返回主页
客观题
0/20
主观题
0/13
做题记录

做题记录

    暂无记录

    答题详情

    一、单选题(10 题)
    第 1 题单选题
    在网络通信中,IP 地址的主要作用是( )。
    A 标识一台主机上的某个应用程序
    B 在网络中标识一台设备(大致唯一)
    C 规定数据编码格式
    D 替代端口号
    第 2 题单选题
    端口号的主要作用是( )。
    A 替代 IP 地址
    B 同一台机器上区分不同程序(进程)使用的"窗口"
    C 保证传输一定可靠
    D 只能是 0~255
    第 3 题单选题
    下列关于 TCP 特点的描述,错误的是( )。
    A 面向连接
    B 可靠传输(有确认、重传、有序等机制)
    C 面向字节流
    D 无连接、发完就走
    第 4 题单选题
    创建 IPv4 + TCP 套接字时,正确的参数组合是( )。
    A socket.AF_INET, socket.SOCK_DGRAM
    B socket.AF_INET, socket.SOCK_STREAM
    C socket.AF_UNIX, socket.SOCK_STREAM
    D socket.AF_INET6, socket.SOCK_DGRAM
    第 5 题单选题
    TCP 服务端建立连接并收发数据,不需要调用的是( )。
    A bind
    B listen
    C accept
    D connect
    第 6 题单选题
    TCP 客户端与服务器通信时,通常使用( )。
    A bind
    B listen
    C connect
    D accept
    第 7 题单选题
    服务端调用 accept() 成功后,应与哪一个套接字进行 recv / send?( )。
    A 监听套接字(listen 用的那个)
    B accept 返回的新套接字
    C 任意一个都可以
    D 必须先 shutdown 再用监听套接字
    第 8 题单选题
    Python 3 中通过 TCP 发送字符串 "你好",正确写法是( )。
    A sock.send("你好")
    B sock.send("你好".encode('utf-8'))
    C sock.write("你好")
    D sock.send(bytes("你好")) 且不指定编码
    第 9 题单选题
    下列关于 TCP recv 的说法,正确的是( )。
    A 一次 recv 一定能收到对方一次 send 的完整"一条消息"
    B 返回 b''(长度为 0)通常表示对端已关闭连接
    C 应对监听套接字调用 recv
    D recv 在 Python 3 中返回 str 类型
    第 10 题单选题
    关于 multiprocessing.Process,下列说法正确的是( )。
    A target=coding()target=coding 没有区别
    B 创建后调用 start() 才会真正启动子进程
    C Windows 下可以不写 if __name__ == '__main__':
    D 多个进程默认共享同一个全局列表的修改
    二、填空题(10 题)
    第 11 题填空题
    一句话概括:IP 找 ,端口找
    第 12 题填空题
    TCP 三大特点:面向连接、可靠传输、面向
    第 13 题填空题
    服务端典型流程口诀:创建 → 绑定 → 监听 → → recv/send → close。
    第 14 题填空题
    bind 的参数必须是 ,形如 (host, port),其中 port 类型。
    第 15 题填空题
    网络上传输的是 类型,接收后常用 还原成字符串。
    第 16 题填空题
    单元素元组传参给 args 时应写成
    第 17 题填空题
    查看当前进程编号常用 os.()
    第 18 题填空题
    子进程中要执行的函数应传给 Process 参数,且不要加括号写成"先执行再传"。
    第 19 题填空题
    默认情况下,多个进程之间 (共享/不共享)全局变量。
    第 20 题填空题
    recv 返回长度为 0 的字节 b'',通常表示对端已 连接。
    三、简答题(7 题)
    第 21 题简答题
    用自己的话说明:为什么 TCP 叫"面向连接",和"打电话"有什么类比?
    查看参考答案 ▼
    TCP 在真正传输应用数据之前,要先经过三次握手在客户端和服务器之间建立一条逻辑上的连接,双方都确认"对方愿意通信、状态就绪"之后,才在这条连接上传字节。这和打电话很像:先拨号、对方接听、双方确认线路通了再说话;而不是像发短信那样随手发出去就不管对方是否收到(那更接近无连接的 UDP)。
    第 22 题简答题
    三次握手要解决什么问题?(可只答要点)
    查看参考答案 ▼
    让通信双方互相知道对方在线且愿意建立连接; 同步双方的初始序号(seq)等连接状态,为后面可靠传输、按序重组打基础; 减少历史残留的旧连接请求或重复报文对本次连接的干扰。三次是在工程上既能完成双方确认、又能对齐状态的一种最小可行握手次数。
    第 23 题简答题
    为什么服务端 accept 后会得到"新套接字",而客户端通常只有一个套接字?
    查看参考答案 ▼
    服务端需要分工:原来的监听套接字专门负责在门口排队接听新的连接请求(listen + 反复 accept);每成功接入一个客户端,accept 会再生成一个已与该客户端建立好连接的新套接字,此后的 recv/send 都在这条"专线"上进行。客户端是主动发起 connect 的一方,从头到尾只用一个套接字与服务器通信。
    第 24 题简答题
    为什么说 TCP 是"面向字节流"?对 send / recv 有什么实际影响?
    查看参考答案 ▼
    TCP 上传输的是连续的字节序列,协议本身不保证"一条业务消息"的边界——你 send 两次,对端不一定两次 recv 各对齐一次发送。实际影响:应用层要自己约定分包规则(如固定长度、先发长度再发内容、用特定分隔符、或短连接一次发完就关)。
    第 25 题简答题
    argskwargs 给子进程传参时各要注意什么?
    查看参考答案 ▼
    args 必须是元组,按位置对应 target 函数的形参;若只有一个参数,必须写成 (x,)(逗号不能省)。kwargs字典键名必须与被调用函数的参数名完全一致,值类型也要合法。
    第 26 题简答题
    为什么默认多个进程不共享全局变量?若要进程间通信通常需要什么思路?
    查看参考答案 ▼
    操作系统以进程为单位分配地址空间,创建子进程时会把父进程的内存做各自独立的拷贝,全局变量在每个进程里其实是自己的一份副本。要在进程间交换数据,需要进程间通信(IPC)手段,例如 multiprocessing 提供的 QueuePipe,或 Manager 托管对象、共享内存等。
    第 27 题简答题
    阅读笔记中"四次挥手"表格,用一段话说明:为什么是四次而不是三次?
    查看参考答案 ▼
    因为 TCP 是全双工通信,每个方向的数据传输需要独立关闭。一方发送 FIN 只表示"我没有数据要发了",但对方可能还有数据要传。因此关闭过程需要四步:
    ① 客户端发 FIN(我没数据了)
    ② 服务端回 ACK(我知道了)——此时服务端可能还在发剩余数据
    ③ 服务端发 FIN(我也没有数据了)
    ④ 客户端回 ACK(我知道了)
    其中②和③不能合并,因为服务端收到 FIN 后可能还需要时间处理并发送剩余数据。而三次握手时双方状态同步可以合并(SYN+ACK),所以是三次而不是四次。
    四、代码实战(6 题)
    第 27 题代码实战
    最简 TCP 一问一答(必做)
    编写服务端:socketbindlistenacceptrecv 打印 → send 回复 → close 通信套接字。
    编写客户端:socketconnectsendrecv 打印 → close
    必须使用 encode('utf-8') / decode('utf-8')
    查看参考答案 ▼
    # 服务端 import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind(('127.0.0.1', 9000)) s.listen(128) conn, addr = s.accept() data = conn.recv(1024).decode('utf-8') print("收到:", data) conn.send("服务器已收到".encode('utf-8')) conn.close() s.close() # 客户端 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()
    第 28 题代码实战
    循环 accept 接待多个客户端(重点必做)
    while True 循环 accept,每接入一个客户端:收一条短消息、回一条"已收到"、关闭与该客户端的通信套接字。
    监听套接字可保持不关闭,便于继续接下一个。
    查看参考答案 ▼
    while True: conn, addr = server.accept() data = conn.recv(1024).decode('utf-8') print(addr, data) conn.send(b'ok') conn.close()
    第 29 题代码实战
    文件上传骨架(重点必做)
    服务端:accept 后以 wb 打开目标文件,循环 recv,将收到的 bytes write 进文件;当 recv 得到 b'' 时退出循环并关闭。
    客户端:以 rb 读本地小文件,循环 send 分块发送,发完 close
    说明"为什么要分块"的原因(注释)。
    查看参考答案 ▼
    # 服务端 conn, _ = server.accept() with open("recv.bin", "wb") as f: while True: chunk = conn.recv(4096) if not chunk: break f.write(chunk) conn.close() # 客户端 with open("src.bin", "rb") as f: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(("127.0.0.1", 9000)) while True: chunk = f.read(4096) if not chunk: break sock.send(chunk) sock.close() # 分块原因:大文件无法一次读入内存, # 分块发送可控制内存占用,避免网络拥塞。
    第 30 题代码实战
    多进程入门(必做)
    定义两个函数,分别打印不同前缀的循环输出。
    multiprocessing.Process 创建两个子进程并 start()
    代码放在 if __name__ == '__main__': 中。
    查看参考答案 ▼
    import multiprocessing def job_a(): for i in range(3): print("A", i) def job_b(): for i in range(3): print("B", i) if __name__ == "__main__": p1 = multiprocessing.Process(target=job_a) p2 = multiprocessing.Process(target=job_b) p1.start() p2.start()
    第 31 题代码实战
    进程传参与 PID(必做)
    编写 work(name, n),打印 name 和循环序号。
    分别用 args=('张三', 5)kwargs 形式各启动一个子进程。
    在子进程内打印 os.getpid(),在主进程打印子进程的 pid
    查看参考答案 ▼
    import os import multiprocessing def work(name, n): print(os.getpid(), name, n) if __name__ == "__main__": p1 = multiprocessing.Process(target=work, args=("张三", 5)) p2 = multiprocessing.Process(target=work, kwargs={"name": "李四", "n": 10}) p1.start() p2.start() print("main:", os.getpid())
    第 32 题代码实战
    多进程/多线程处理客户端(选做)
    尝试在服务端 accept 后使用子进程(或线程)处理单个客户端,避免"一个人聊很久别人排队"(写出思路或伪代码即可)。
    查看参考答案 ▼
    # 思路:每 accept 一个客户端就 fork 一个子进程去处理 # 主进程继续 accept,子进程负责与该客户端通信 import socket import multiprocessing def handle_client(conn, addr): """子进程:处理单个客户端的通信""" print(f"[子进程] 处理 {addr}") while True: data = conn.recv(1024) if not data: break print(f"{addr}: {data.decode('utf-8')}") conn.send(b"received") conn.close() print(f"[子进程] {addr} 断开") if __name__ == "__main__": server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind(('0.0.0.0', 9000)) server.listen(128) print("服务器启动,等待连接...") while True: conn, addr = server.accept() # 创建子进程处理该客户端 p = multiprocessing.Process(target=handle_client, args=(conn, addr)) p.start() # 主进程继续 accept,不阻塞 # 也可以用 threading.Thread 替代 Process, # 线程更轻量但受 GIL 限制;进程隔离更好但开销更大。