实验三 Socket编程技术
20191130李月 《Python程序设计》实验三报告
课程:《Python程序设计》
班级: 1911
姓名: 李月
学号:20191130
实验教师:王志强
实验日期:2020年5月31日
必修/选修: 公选课
(一)实验内容
创建服务端和客户端,服务端在特定端口监听多个客户请求。客户端和服务端通过Socket套接字(TCP/UDP)进行通信。
(1)创建服务端和客户端,选择一个通信端口,用Python语言编程实现通信演示程序;
(2)要求包含文件的基本操作,例如打开和读写操作。
(3)要求发送方从文件读取内容,加密后并传输;接收方收到密文并解密,保存在文件中。
(二)实验过程及结果
1)监听多个客户端
为了多个客户端多线并行从而采取了线程处理的方式,将监听放入主线程,将处理放入子线程。
SerSock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
SerSock.bind(('127.0.0.1',8001))
SerSock.listen(5)
socks = [] # 存放每个客户端的socket
t = threading.Thread(target=handle)
if __name__ == '__main__':
t.start()
print(r'我在%s线程中' % threading.current_thread().name)
print('waiting for connecting ...')
while True:
CliSock,addr = SerSock.accept()
print('connected from:',addr)
socks.append(CliSock)
2)客户端连接服务器
CliSock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
serve_ip = input("Please enter the server IP:")
serve_port = int(input("Please enter the corresponding Port:")) # 端口要是int类型,所有要转换
CliSock.connect((serve_ip, serve_port)) # 连接服务器,建立连接,参数是元组形式
3)通讯循环
为了使通讯可以不断进行,并在需要的时候停止,进行了如下设置。
while True:
send_data = input("Enter your message:")
CliSock.send(send_data.encode('utf-8'))
time.sleep(1)
if send_data == 'quit':
print('\ncommunication ended.')
break
elif send_data == 'encrypt file':
filename = input("Please enter the file name:")
print("If the file is large, the run time will be a little long, please be patient.")
af_filename = 'Client encrypted.txt'
time.sleep(1)
send_out(filename)
take_in(af_filename)
decrypt(af_filename)
print('')
re = CliSock.recv(1024)
print("Server is sending:",re.decode('utf-8'))
4)文件发送与接收
为了提高将二者都变为函数,因为传输前后顺序不同,相关的代码也会有所不同。
客户端相关代码
在本实验中的传输文件代码只能传输本目录下的相关文件。
传输代码
def send_out(filename):
with open(filename, 'rb') as file:
for i in file:
CliSock.send(i)
data = CliSock.recv(1024)
if data != b'success':
break
time.sleep(1)
CliSock.send('quit'.encode())
print("... File sent successfully ...")
接收代码
def take_in(af_filename):
while True:
with open(af_filename, 'ab') as file:
data = CliSock.recv(1024)
if data == b'quit':
break
file.write(data)
time.sleep(1)
CliSock.sendall('success'.encode())
print("... File reception completed ...")
服务端相关代码
传输代码
def send_out(filename,s):
with open(filename, 'rb') as file:
i = file.read()
s.send(i)
time.sleep(1)
s.send('quit'.encode())
print("... File sent successfully ...")
接收代码
def take_in(filename,s):
while True:
with open(filename, 'ab') as file:
data = s.recv(1024)
if data == b'quit':
break
file.write(data)
time.sleep(1)
s.sendall('success'.encode())
print("... File reception completed ...")
5)文件的加密以及解密
加密代码
def encrypt(filename,af_filename):#加密方法
key = input("Please set a key:")
text = open(filename,'rb').read()
open(filename,'rb').close()
text = str(text)
aes = AES.new(add_to_16(key), AES.MODE_ECB)
encrypt_aes = aes.encrypt(add_to_16(text))
encrypted_text = str(base64.encodebytes(encrypt_aes), encoding='utf-8')
logbat = open(af_filename, 'w')
logbat.write(encrypted_text)
logbat.close()
print('... File encrypted successfully ...')
解密代码
def decrypt(af_filename):
key = input('Please enter the corresponding key:')
text = str(open(af_filename, 'r').read()) # 密文文件
open(af_filename, 'r').close()
aes = AES.new(add_to_16(key), AES.MODE_ECB) # 初始化加密器
base64_decrypted = base64.decodebytes(text.encode(encoding='utf-8')) # 优先逆向解密base64成bytes
decrypted_text = str(aes.decrypt(base64_decrypted), errors='ignore').replace('\0', '') # 执行解密
decrypted_text2 = eval(decrypted_text)
decrypted_text3 = decrypted_text2.decode('utf-8')
print("Successfully decrypted, the contents of the file are:")
print(decrypted_text3)
补足key位数的相关函数代码
在内部实现上,AES只是提供一个接收固定长度密钥和16字节大小的分组,然后生成另外一个不同的16字节大小的分组的数学函数。
def add_to_16(value):# str不是16的倍数那就补足为16的倍数
while len(value) % 16 != 0:
value += '\0'
return str.encode(value) # 返回bytes
(三)思考感悟
1、一个程序的产生要经历不断地修改。
2、在开始编写程序之前需要把基础知识掌握牢固。
3、编写程序的时候可以采用自顶向下、逐步求精。
4、编写程序需要耐心、细心。