首先上本机实测截图
如果对linux基础命令都不太熟悉的话,那就先学习基础命令吧,要不然你也不清楚我敲这几个简单的命令是为啥子
下面上服务端的代码
#! /usr/bin/env python3
# -*- coding:utf-8 -*-
import socket
import threading
import pretty_errors # 一个错误模块,导入即可,它会把错误的信息显示的五颜六色的
import os, sys, os.path
import time # 如果是linux服务器,则很有可能需要time.sleep(0.1),原因还不太清楚
import struct # 本来传输数字应该就这个模块的,但是不太熟,所以最终未用
import json
import readline # 如果此脚本运行在linux服务器上,为了输入方便,则导入此模块
import signal
import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s', filename="fileserver.log")
pidFile = "/var/run/fileserver.pid"
# 获取socket对象,如果觉得这样写麻烦,可以不用写在方法里面,直接写在外面即可
def sock_obj() -> socket:
addr_port = ("0.0.0.0", 8989)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 关闭连接后马上释放端口
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(addr_port)
s.listen(5)
return s
# 这个方法用于接收文件的字节,目前是单线程的,一次只能有一个人上传
# 这里的想法是三步骤:
# 第一步:接收文件名字和大小的字节的长度(有点拗口哈,我也不知道怎么说,反正就是一个数字)
# 第二步:接收实际文件的名字和大小的数据
# 第三步:接收实际文件的内容
def recv_file(sock, addr, dirname) -> None: #这里的 addr参数可以不要,因为我这里未用
tcp_min_len = 0
tcp_head_msg = b""
tcp_head = sock.recv(1024)
tcp_head_len = struct.unpack(">H", tcp_head)
time.sleep(0.1)
while tcp_min_len < int(tcp_head_len[0]):
msg = sock.recv(1024)
tcp_min_len += len(msg)
tcp_head_msg += msg
#print("%s:%s上传的文件名是:%s,文件大小是:%0.2fG" % (addr[0], addr[1], json.loads(tcp_head_msg.decode("utf-8"))["name"], int(json.loads(tcp_head_msg.decode("utf-8"))["size"]) / 1024 / 1024 / 1024))
logging.info("%s:%s上传的文件名是:%s,文件大小是:%0.2fG" % (addr[0], addr[1], json.loads(tcp_head_msg.decode("utf-8"))["name"], int(json.loads(tcp_head_msg.decode("utf-8"))["size"]) / 1024 ** 3))
tcp_head_dict = json.loads(tcp_head_msg.decode("utf-8"))
file_min_len = 0
with open(os.path.join(dirname, tcp_head_dict["name"]), "wb") as wf:
while file_min_len < int(tcp_head_dict["size"]):
file_data = sock.recv(4096)
file_min_len += len(file_data)
wf.write(file_data)
#print("%s 上传完毕" % json.loads(tcp_head_msg.decode("utf-8"))["name"])
logging.info("%s 上传完毕" % json.loads(tcp_head_msg.decode("utf-8"))["name"])
def while_msg(sock, addr, dir_name) -> None:
#print("%s:%s进来了" % addr)
logging.info("%s:%s进来了" % addr)
while True:
try:
recv_file(sock, addr, dir_name)
except ConnectionResetError:
#print("%s:%s退出" % addr)
logging.info("%s:%s退出" % addr)
break
def start_sock(dir_name) -> None:
print("服务端准备就绪......")
logging.info("服务端准备就绪......")
while True:
sock, addr = sock_obj().accept()
t = threading.Thread(target=while_msg, args=(sock, addr, dir_name))
t.start()
def h() -> str:
h = """ 1,脚本用python3编写,未测试是否支持python2
2,此脚本只能运行再类unix系统上
------------------------------------------------
3,运行此脚本的方式:python3 fileserver.py start
4,停止此脚本的方式:python3 fileserver.py stop
"""
print(h)
def get_pid() -> int:
if os.path.exists(pidFile):
with open(pidFile, "r") as f:
return int(f.read())
else:
return 0
def set_pid(pid) -> None:
with open(pidFile, "w") as f:
f.write(str(pid))
if __name__ == "__main__":
if sys.argv[1] == "help":
h()
elif sys.argv[1] == "start":
# 这里大家可以换成参数的形式,我这里就不作了,反正只是测试功能,又不是要完善功能
#while True:
# dir_name = input("please enter dir:")
# if not os.path.isdir(dir_name):continue
# break
dir_name = "/opt"
if os.fork() > 0:
os._exit(0)
set_pid(os.getpid())
start_sock(dir_name)
elif sys.argv[1] == "stop":
if get_pid() == 0:print("服务端并未启动")
else:
now_pid = os.popen("ps axu | grep %s | grep -v grep" % get_pid()).read()
if now_pid == "":
print("服务端并未启动")
os.popen("rm -rf %s" % pidFile)
else:
print("退出进程")
logging.info("退出进程")
os.kill(get_pid(), signal.SIGKILL)
os.popen("rm -rf %s" % pidFile)
else:
print("参数错误,使用方法详见 help")
下面是客户端的代码
#! /usr/bin/env python3
# -*- coding:utf-8 -*-
import pretty_errors
import os, os.path
import socket
import json
import struct
import time
from tqdm import tqdm
def is_file(path) -> bool:
if os.path.exists(path):
if os.path.isfile(path):
return True
else:
return False
else:
return False
def get_file_json(path) -> json:
file_size = os.path.getsize(path)
file_name = os.path.basename(path)
file_dict = {"size": file_size, "name": file_name}
return json.dumps(file_dict)
def send_file(sock) -> None:
buff_size = 4096
while True:
file_path = input("please enter file path:")
if not is_file(file_path): continue
break
file_struct = struct.pack(">H", len(get_file_json(file_path).encode("utf-8")))
sock.send(file_struct)
time.sleep(0.1)
sock.send(get_file_json(file_path).encode("utf-8"))
time.sleep(0.1)
with open(file_path, "rb") as rf:
for i in tqdm(range(int(json.loads(get_file_json(file_path))["size"]) // buff_size + 1)):
sock.send(rf.read(buff_size))
print("send end")
if __name__ == "__main__":
# addr = "172.30.0.161"
addr = input("please enter id address:")
port = 8989
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((addr, port))
while True:
try:
send_file(s)
except ConnectionResetError:
print("客户端退出")
break