计算机网络实验二 网络基础编程实验(Python3)
由于这一次实验2.1-2.3都是给了代码的,所以没有写了,只写了2.3的对比和2.4的代码,实现互通信
2.3 多线程/线程池对比(python3.5)
- 多线程:每处理一个socket请求都会新建一个线程 类似于临时工简单的为每一个socket都开一个线程,将socket作为参数传进去即可。优点:合理利用CPU资源。并且可以提高程序的运行效率缺点:如果有大量的线程运行,会消耗大部分内存,会影响性能(可能会死机),CPU需要他们之间的切换线程运行可能会出现死锁、线程安全问题
- 线程池:提前创建好多个线程,然后需要就从线程池里拿,用完换回去即可 类似于长期工优点:如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程,并且大量线程空闲,就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。这个时候,线程池的作用就出来了,当程序需要创建大量生命周期很短暂的线程时,使用线程池可以有效控制系统中并发线程的数量,线程池中,一个线程于空闲状态时,可以被使用,使用时变为阻塞状态,使用后又变成空闲状态,这样就可以实现线程的重复利用
多线程与单线程的传输连接的不同点也在于连接的声明方式,即为每一个连接客户端建立一个线程,连接将使用Threading方法,被如下声明:
2.4 写一个简单的chat程序,并能互传文件,编程语言不限。
先放效果图(真的很傻,但是够应付实验了)
#!/usr/bin/env python
#coding:utf-8
import socket
import sys
import os
ip_port = ('127.0.0.1',9999)
sk = socket.socket()
sk.connect(ip_port)
base_path = 'E:\\Junior_1\计算机网络\lab2'
container = {'key':'','data':''}
while True:
FLAG = input('0.收文件存到basepath下 1.传path目录下文件存到srv的basepath1下\n')
sk.sendall(str(FLAG).encode('utf-8'))
if FLAG=='1':
# 客户端输入要上传文件的路径
path = 'E:\\qq_file_receive\pic.gif'
# 根据路径获取文件名
file_name = os.path.basename(path)
# print(file_name)
# 获取文件大小
file_size = os.stat(path).st_size
# 发送文件名 和 文件大小
Informf = (file_name + '|' + str(file_size))
sk.send(Informf.encode())
# 为了防止粘包,将文件名和大小发送过去之后,等待服务端收到,直到从服务端接受一个信号(说明服务端已经收到)
message=sk.recv(1024)
print(message.decode())
send_size = 0
f = open(path, 'rb')
Flag = True
while Flag:
if send_size + 1024 > file_size:
data = f.read(file_size - send_size)
Flag = False
else:
data = f.read(1024)
send_size += 1024
sk.send(data)
msg = sk.recv(1024)
print(msg.decode())
f.close()
else :
message=sk.recv(1024)
print(message.decode(encoding='utf8'))
message = input('请求文件名: ')
message = str(message)
# 发送数据 加码
sk.sendall(message.encode('utf-8'))
print('A等待.....')
pre_data = sk.recv(1024).decode()
# 获取请求方法、文件名、文件大小
file_name, file_size = pre_data.split('|')
# 防止粘包,给客户端发送一个信号。
sk.sendall('get'.encode())
# 已经接收文件的大小
recv_size = 0
# 上传文件路径拼接
file_dir = os.path.join(base_path, message)
f = open(file_dir, 'wb')
Flag = True
while Flag:
# 未上传完毕,
if int(file_size) > recv_size:
# 最多接收1024,可能接收的小于1024
data = sk.recv(1024)
recv_size += len(data)
# 写入文件
f.write(data)
# 上传完毕,则退出循环
else:
recv_size = 0
Flag = False
sk.sendall('下载完成'.encode())
print('upload successed.')
f.close()
sk.close()
#!/usr/bin/env python
#coding:utf-8
import socketserver
import os
class MyServer(socketserver.BaseRequestHandler):
def handle(self):
base_path = 'E:\\Junior_1\计算机网络'
conn = self.request
print ('connected...')
while True:
order = conn.recv(1024).decode(encoding='utf8')
print(order)
if order == '1':
pre_data = conn.recv(1024).decode()
# 获取请求方法、文件名、文件大小
file_name, file_size = pre_data.split('|')
# 防止粘包,给客户端发送一个信号。
conn.sendall('收到'.encode())
# 已经接收文件的大小
recv_size = 0
# 上传文件路径拼接
file_dir = os.path.join(base_path, file_name)
f = open(file_dir, 'wb')
Flag = True
while Flag:
# 未上传完毕,
if int(file_size) > recv_size:
# 最多接收1024,可能接收的小于1024
data = conn.recv(1024)
recv_size += len(data)
# 写入文件
f.write(data)
# 上传完毕,则退出循环
else:
recv_size = 0
Flag = False
conn.sendall('下载完成'.encode())
print('upload successed.')
f.close()
if order == '0':
conn.sendall('B准备发送文件啦'.encode('utf-8'))
path = conn.recv(1024).decode()
file_name = os.path.join(base_path, path)
print(file_name)
# file_name = os.path.basename(path)
# print(file_name)
# 获取文件大小
file_size = os.stat(file_name).st_size
# 发送文件名 和 文件大小
Informf = (file_name + '|' + str(file_size))
conn.send(Informf.encode())
# 为了防止粘包,将文件名和大小发送过去之后,等待服务端收到,直到从服务端接受一个信号(说明服务端已经收到)
me=conn.recv(1024).decode()
print(me)
send_size = 0
f = open(file_name, 'rb')
Flag = True
while Flag:
if send_size + 1024 > file_size:
data = f.read(file_size - send_size)
Flag = False
else:
data = f.read(1024)
send_size += 1024
conn.send(data)
conn.recv(1024)
f.close()
instance = socketserver.ThreadingTCPServer(('127.0.0.1',9999),MyServer)
instance.serve_forever()
#(服务端)
可能有线程安全问题,搞多线程又不标识线程号不保护,但是实验二应该也不会要求这么多把。
反正一个线程跑是莫得问题的