20241307 实验三 《Python程序设计》实验报告
20241307 2024-2025-2 《Python程序设计》实验三报告
课程:《Python程序设计》
班级: 2413
姓名: 张岳峰
学号:20241307
实验教师:王志强
实验日期:2025年4月16日
必修/选修: 公选课
1.实验内容
1.创建服务端和客户端,服务端在特定端口监听多个客户请求。客户端和服务端通过Socket套接字(TCP/UDP)进行通信。
2.创建服务端和客户端,选择一个通信端口,用Python语言编程实现通信演示程序;
3.要求包含文件的基本操作,例如打开和读写操作。
4.要求发送方从文件读取内容,加密后并传输;接收方收到密文并解密,保存在文件中。
5.程序代码托管到码云。
2. 实验过程及结果
实验准备
在windows或python终端输入ipconfig,在IPv4获取服务端ip地址,用于服务端和客户端的连接。
首先将我的设备作为服务端,ip地址为192.168.0.216

一、服务端代码设计
核心思路如下:
1. 导入模块
import socket:引入Python的socket模块,该模块提供了底层网络通信功能,是实现网络服务端的基础。
2. 创建套接字
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) :创建一个TCP类型(SOCK_STREAM )的套接字,AF_INET 表示使用IPv4地址 ,是网络通信中建立连接的基本对象。
3. 地址绑定
address = ('192.168.42.220', 8888)(宿舍断网了,这里用的热点,重新查询ip地址)
server_socket.bind(address)
指定服务端监听的IP地址(192.168.42.220 )和端口号(8888 ),并通过bind方法将套接字与该地址锁定,让服务端知道在哪等待客户端连接。
4. 监听连接
server_socket.listen(5) :使服务端开始监听指定地址和端口,参数5表示允许的未完成连接队列的最大长度 ,最多可以同时有5个客户端处于等待连接状态。
5. 接收连接
client_socket, address = server_socket.accept()
print("我们收到了{}的连接.".format(address))
accept方法会阻碍程序执行,直到有客户端发起连接请求。一旦有客户端连接,它会返回一个新的套接字对象(client_socket )用于与该客户端进行通信,同时返回客户端的地址信息(address ) 。
6. 数据交互
while True:
data = client_socket.recv(1024)
if not data:
break
print("客户端说: {}".format(data.decode()))
response = input("服务端回应: ")
client_socket.send(response.encode())
通过一个循环持续与客户端进行数据交互。recv(1024) 从客户端接收最多1024字节的数据 ,如果没有接收到数据就跳出循环。接收到数据后先解码并打印,然后等待用户输入服务端的响应内容,再将响应内容编码后发送给客户端。
7. 关闭连接
client_socket.close()
server_socket.close()
在通信结束后,关闭与客户端通信的套接字(client_socket )以及服务端监听的套接字(server_socket ),释放内存。
代码如下!:
监听成功,结果如下:

二、客户端代码设计
核心思路如下:
1. 导入模块
import socket:导入Python的socket模块,模块提供了网络通信相关功能,是实现客户端网络连接与数据交互的基础。
2. 创建套接字
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) :创建一个TCP类型(SOCK_STREAM )的套接字,使用IPv4地址(AF_INET ) ,用于后续与服务端建立连接和数据传输。
3. 连接服务端
client_socket.connect(('192.168.42.248', 8888)) :让客户端套接字连接到准备环节ipconfig地址(192.168.42.248 )和端口号(8888 ),之前用的端口9999,(竟然不能用了,一个端口不能重复使用啊)的服务端,建立起网络连接。
4. 数据交互循环
while True:
message = input("客户端说: ")
if message.lower() == 'exit':
break
client_socket.send(message.encode())
data = client_socket.recv(1024).decode()
print("服务端回答: ", data)
- 发送消息:通过
input函数获取用户在客户端输入的内容,赋值给message。若message经转换为小写后等于'exit',则跳出循环结束通信;否则将message编码后通过send方法发送给服务端。 - 接收回复:使用
recv(1024)接收服务端返回的数据,并对接收的数据进行解码,然后打印出服务端的回答。
5. 关闭连接
client_socket.close() :当数据交互完成(比如用户输入exit )后,关闭客户端套接字,释放相关网络资源。
代码如下:

连接成功,结果如下:

三、加密、解密算法及文件操作的综合运用
1.实验准备
(1)查看当前我的ip地址,为192.168.0.216

(2)查看我的服务端、客户端python文件在文件夹下的的绝对路径,以便加密、解密成功后产生的文件保存操作
路径如下:


2.服务端代码设计
核心思路如下:
1. 导入模块
import socket:引入Python的socket模块,用于进行网络通信,是实现服务端与客户端交互的基础。
2. 加密解密函数定义
def encrypt_decrypt(data, key):
result = ""
for char in data:
result += chr(ord(char) ^ key)
return result
定义了encrypt_decrypt函数,实现异或加密解密功能。遍历输入字符串data的每个字符,将字符的Unicode码点与密钥key进行异或运算,再将运算结果转换回字符并拼接起来,最后返回处理后的字符串。
3. 创建套接字
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) :创建一个基于IPv4(AF_INET )的TCP(SOCK_STREAM )套接字,为后续网络连接做准备。
4. 地址绑定与监听
address = ('192.168.0.216', 8888)
server_socket.bind(address)
server_socket.listen(5)
指定服务端监听的IP地址(192.168.0.216 )和端口号(8888 ),通过bind方法将套接字与地址绑定,然后使用listen方法开始监听,参数5表示允许的未完成连接队列的最大长度。
5. 接收连接
client_socket, address = server_socket.accept()
print('我们收到了{}的连接.'.format(address))
accept方法会阻碍程序,直到有客户端发起连接请求。当有客户端连接时,返回用于与该客户端通信的套接字对象(client_socket )和客户端地址(address ) ,并打印连接信息。
6. 数据交互与处理
while True:
data1 = client_socket.recv(1024)
if not data1:
break
decoded_data = data1.decode()
print("客户端说: {}".format(decoded_data))
data2 = encrypt_decrypt(decoded_data, 666)
print(data2)
file_path = r'C:\Users\ZB\PycharmProjects\20241307-zhang-yuefeng\.venv\serve.txt'
- 接收数据:通过循环持续接收客户端发送的数据,若未接收到数据则跳出循环。接收到的数据先解码并打印。
- 数据处理:使用定义好的
encrypt_decrypt函数,以密钥666对解码后的数据进行处理既可以理解为加密,也可用于解密,并打印处理后的数据。 - 文件操作:代码中指定了文件路径
file_pathC:\Users\ZB\PycharmProjects\20241307-zhang-yuefeng.venv\服务端.py ,将解密后的数据保存到文件夹中。
7. 关闭连接
代码中缺少关闭套接字连接的相关语句(如client_socket.close() 和server_socket.close() ),正常情况下在通信结束后,需要关闭相关套接字以释放内存等。
代码如下:

3.客户端代码设计
核心思路如下:
1. 导入模块
import socket:导入socket模块,实现客户端与服务端的网络通信提供基础功能。
2. 加密解密函数定义
def encrypt_decrypt(data, key):
result = ""
for char in data:
result += chr(ord(char) ^ key)
return result
定义encrypt_decrypt函数,利用异或运算实现加密和解密功能。遍历输入字符串data的每个字符,将字符的Unicode码点与密钥key进行异或运算,把运算结果转换为字符之后拼接起来,最后返回处理后的字符串。
3. 文件操作
file_path = r'C:\Users\ZB\PycharmProjects\20241307-zhang-yuefeng\.venv\text.txt'
with open(file_path, 'w') as file:
file.write('Hello, World!')
指定文件路径file_path ,使用with语句以写入模式打开文件,向文件中写入'Hello, World!' 。后续又以读取模式打开该文件,读取文件内容到data2 ,为后续加密传输做准备。
4. 创建套接字
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) :创建一个基于IPv4(AF_INET )的TCP(SOCK_STREAM )套接字,用于建立与服务端的网络连接。
5. 连接服务端
client_socket.connect(('192.168.0.216', 8888)) :使客户端套接字连接到指定IP地址(192.168.0.216 )和端口号(8888 )的服务端,建立网络通信链路。
6. 数据交互循环
while True:
message = input("如果想要退出输入exit,如果不,输入no:")
if message.lower() == 'exit':
break
with open(file_path, 'r') as file:
data2 = file.read()
encrypted_data = encrypt_decrypt(data2, 666)
client_socket.send(encrypted_data.encode())
- 输入判断:通过
input获取用户输入,若用户输入exit(不区分大小写 ),则跳出循环结束通信。 - 文件读取与加密:每次循环都以读取模式打开指定文件,读取文件内容,然后使用
encrypt_decrypt函数,以密钥666对读取到的文件内容进行加密。 - 数据发送:将加密后的数据编码为字节流,通过套接字发送给服务端。
7. 关闭连接
client_socket.close() :当数据交互完成(用户输入exit )后,关闭客户端套接字,释放网络资源。
代码如下:
实验结果如下:


写入文件如下:


程序代码托管到码云


3. 实验过程中遇到的问题和解决过程
- 问题1:无法上传至git库,一上传就报错,上传成功在个人gitee仓库也找不到代码
- 问题1解决方案:在实验一配置过的项目创建新的python程序文件,重新链接git库上传并推送源程序,查询资料得知应该以管理员身份运行PyCharm才能上传。
- 问题2:服务端没法监听客户端,并报出以下错误

- 问题2解决方案:询问老师我得知要关闭电脑的所有防火墙,我的电脑没有这个选项,询问豆包之后先关闭了系统防护,然后关闭所有防火墙,并更改了端口号为‘8888’,因为端口号重复应用了,这一次成功监听

- 问题3:文件加密、解密成功后没有写入.text后缀的文件到目录文件夹,找不到成功解码获得的文件
- 问题3解决方案:看视频问AI,在pycharm中右键python文件可以查看绝对路径,将该路径写入到代码文件写入操作的地址,就可以在python程序运行后获得.text后缀加密、解密的文件


- 问题4:python语法运用不熟练,编写程序报错,
- 问题4解决方案:看教材问AI,学习了python的常见文件操作语句、
Python常用的文件操作
打开文件
使用open()函数来打开文件,基本语法为file = open('文件路径', '模式') 。常用文件打开模式有:
- r:读取模式(默认),文件必须存在,从文件开头读取。
- r+:读写模式,文件必须存在,可读写,文件指针在开头。
- w:写入模式,如果文件不存在则创建,存在则覆盖原内容。
- w+:读写模式,如果文件不存在则创建,存在则覆盖原内容。
- a:追加模式,如果文件不存在则创建,存在则在文件末尾追加内容。
- b:二进制模式,常与其他模式结合,如
'rb'(二进制读)、'wb'(二进制写) 。
读取文件
读取整个文件
使用read()方法 。
with open('test.txt', encoding='utf-8') as f:
content = f.read()
print(content)
读取一行
使用readline()方法 。
with open('test.txt', encoding='utf-8') as f:
line = f.readline()
print(line)
读取所有行
使用readlines()方法,返回包含每行内容的列表 。示例:
with open('test.txt', encoding='utf-8') as f:
lines = f.readlines()
for line in lines:
print(line)
写入文件
使用write()方法写入内容。
覆盖写入
with open('test.txt', 'w', encoding='utf-8') as f:
f.write('新的内容')
追加写入
with open('test.txt', 'a', encoding='utf-8') as f:
f.write('追加的内容')
文件指针操作
获取当前位置
使用tell()方法获取文件指针当前位置)。
with open('test.txt', 'r', encoding='utf-8') as f:
f.read(5)
pos = f.tell()
print(pos)
移动文件指针
使用seek(offset, whence)方法移动指针。offset是偏移量,whence是基准点(0为文件开头,1为当前位置,2为文件末尾 )。
with open('test.txt', 'r', encoding='utf-8') as f:
f.seek(3, 0) # 从文件开头偏移3个字节
data = f.read(2)
print(data)
关闭文件
使用close()方法关闭文件,建议使用with语句,它会自动处理文件的打开和关闭,无需手动调用close() 。如:
with open('test.txt', 'r', encoding='utf-8') as f:
content = f.read()
目录操作(借助os模块 )
创建目录
os.mkdir('目录名'):创建单级目录。os.makedirs('多级目录名'):创建多级目录。
删除目录
os.rmdir('目录名'):删除单级空目录。os.removedirs('多级目录名'):删除多级目录(目录需为空 )。
列出目录下文件
os.listdir('目录路径')返回目录下所有文件和子目录名称列表 。
判断文件/目录是否存在
os.path.exists('路径') ,存在返回True,否则返回False 。
其他操作
- 重命名文件:
os.rename('旧文件名', '新文件名')。 - 删除文件:
os.remove('文件名')。 - 获取文件大小:
os.path.getsize('文件路径'),返回文件大小(字节为单位 )。
其他(感悟、思考等)
做实验的过程中,我会遇到和老师带着写代码时遇到不一样、全新的问题,这些设计代码、写代码、调试代码、获得结果的过程中,促使我不断思考,查询资料,问老师、问同学、问AI,看视频学习,在这过程中不断强化我对代码的理解,以及对代码编写的熟练度,让我编写代码的能力获得极大的提高。