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,看视频学习,在这过程中不断强化我对代码的理解,以及对代码编写的熟练度,让我编写代码的能力获得极大的提高。

参考资料

posted @ 2025-04-28 20:07  20241307张岳峰  阅读(37)  评论(0)    收藏  举报