Response_Code = 500 Error_Message = Internal Server Error

本文提供了一种解决方法,用于修复使用Selenium时出现的500内部服务器错误。通过调整Selenium初始化代码,可以有效地避免此类问题。
将代码修改如下可以解决Response_Code = 500 Error_Message = Internal Server Error:
selenium = new DefaultSelenium("localhost", port, browserString, url) {
public void open(String url) {
commandProcessor.doCommand("open", new String[] {url,"true"});
}
};
继续修改以下代码,目前企业微信@机器人无法实现重启子程序 import subprocess import threading import time import requests import json import logging import os import signal import psutil from flask import Flask, request, jsonify # 配置日志 logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', handlers=[ logging.StreamHandler() ] ) logger = logging.getLogger("MainProgram") # 企业微信机器人配置 WECHAT_WEBHOOK = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=9ccdb6cc-5a44-4865-b442-7d7c184a6ccd" REQUEST_TIMEOUT = 10 # 网络请求超时时间(秒) # 全局状态 subprocess_proc = None subprocess_active = False last_error = None app = Flask(__name__) def send_wechat_alert(message): """通过企业微信机器人发送警报(带超时机制)""" headers = {"Content-Type": "application/json"} payload = { "msgtype": "text", "text": { "content": message, "mentioned_mobile_list": ["@all"] } } try: # 添加超时参数 response = requests.post( WECHAT_WEBHOOK, data=json.dumps(payload), headers=headers, timeout=REQUEST_TIMEOUT ) if response.status_code == 200: logger.info("企业微信警报发送成功") else: logger.error(f"企业微信发送失败: {response.status_code} - {response.text}") except requests.exceptions.Timeout: logger.error("企业微信请求超时") except requests.exceptions.RequestException as e: logger.error(f"发送企业微信警报时出错: {str(e)}") def start_subprogram(): """启动子程序(增强健壮性)""" global subprocess_proc, subprocess_active try: # 确保之前的进程已终止 if subprocess_proc and subprocess_proc.poll() is None: force_kill_process(subprocess_proc.pid) # 启动新进程 subprocess_proc = subprocess.Popen( ["python", "Generating Task Simulator.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, bufsize=1, # 行缓冲 universal_newlines=True ) subprocess_active = True logger.info("子程序已启动") send_wechat_alert("🚀 子程序已成功启动") return True except Exception as e: logger.error(f"启动子程序失败: {str(e)}") send_wechat_alert(f"❌ 子程序启动失败: {str(e)}") return False def stop_subprogram(): """停止子程序(增强强制终止能力)""" global subprocess_proc, subprocess_active if subprocess_proc and subprocess_active: try: # 尝试优雅终止 subprocess_proc.terminate() # 等待最多5秒 try: subprocess_proc.wait(timeout=5) except subprocess.TimeoutExpired: logger.warning("子程序未响应终止信号,尝试强制终止") force_kill_process(subprocess_proc.pid) subprocess_active = False logger.info("子程序已停止") send_wechat_alert("🛑 子程序已停止") return True except Exception as e: logger.error(f"停止子程序失败: {str(e)}") send_wechat_alert(f"❌ 停止子程序失败: {str(e)}") return False return True def force_kill_process(pid): """强制终止进程及其所有子进程""" try: parent = psutil.Process(pid) children = parent.children(recursive=True) # 先终止子进程 for child in children: try: child.terminate() except psutil.NoSuchProcess: pass # 等待子进程终止 gone, alive = psutil.wait_procs(children, timeout=5) # 强制终止剩余进程 for p in alive: p.kill() # 终止主进程 try: parent.terminate() parent.wait(timeout=3) except psutil.NoSuchProcess: pass logger.info(f"已强制终止进程树 PID: {pid}") return True except Exception as e: logger.error(f"强制终止进程失败: {str(e)}") return False def monitor_subprocess(): """监控子程序状态和输出(增强健壮性)""" global last_error while True: try: if subprocess_proc and subprocess_active: # 检查子程序是否已退出 return_code = subprocess_proc.poll() if return_code is not None: logger.error(f"子程序意外退出,返回码: {return_code}") send_wechat_alert(f"⚠️ 子程序意外退出! 返回码: {return_code}") start_subprogram() # 自动重启 # 非阻塞读取错误输出 while True: line = subprocess_proc.stderr.readline().strip() if not line: break if "SUB_ERROR:" in line: error_msg = line.split("SUB_ERROR:")[1].strip() logger.error(f"检测到子程序错误: {error_msg}") if error_msg != last_error: # 避免重复发送相同错误 send_wechat_alert(f"🔥 子程序错误:\n{error_msg}") last_error = error_msg except Exception as e: logger.error(f"监控线程出错: {str(e)}") time.sleep(5) # 出错后等待 time.sleep(1) # 每秒检查一次 @app.route('/wechat', methods=['POST']) def wechat_command(): """接收企业微信机器人指令(带超时处理)""" try: data = request.json if not data: return jsonify({"error": "Invalid request"}), 400 command = data.get("text", "").strip().lower() user = data.get("from", {}).get("name", "未知用户") response_text = "" if "重启" in command: if stop_subprogram(): time.sleep(1) if start_subprogram(): response_text = f"{user} 已重启子程序 ✅" else: response_text = f"{user} 重启失败 ❌" else: response_text = f"{user} 重启失败 ❌" elif "停止" in command: if stop_subprogram(): response_text = f"{user} 已停止子程序 ⛔" else: response_text = f"{user} 停止子程序失败 ❌" elif "状态" in command: status = "运行中 ✅" if subprocess_active else "已停止 ⛔" last_error_info = f"\n最后错误: {last_error}" if last_error else "" response_text = f"子程序状态: {status}{last_error_info}" else: response_text = "可用命令: 重启, 停止, 状态" return jsonify({ "msgtype": "text", "text": {"content": response_text} }) except Exception as e: logger.error(f"处理微信命令时出错: {str(e)}") return jsonify({"error": "Internal server error"}), 500 if __name__ == "__main__": # 启动子程序 start_subprogram() # 启动监控线程 monitor_thread = threading.Thread(target=monitor_subprocess, daemon=True) monitor_thread.start() logger.info("主程序监控已启动") logger.info("Flask 指令服务器监听中...") # 启动Flask服务器(添加线程支持) app.run(host='0.0.0.0', port=5000, threaded=True)
08-07
from concurrent.futures import ThreadPoolExecutor import multiprocessing import multiprocessing.queues import threading import time import asyncio import numpy as np import grpc from grpc import aio import argparse import os import video_service_pb2 import video_service_pb2_grpc class FPSCounter: def __init__(self, window_size=0.5): self.window_size = window_size # in seconds self.frame_timestamps = [] self.last_print_time = time.time() def add_frame(self): now = time.time() self.frame_timestamps.append(now) # Remove frames older than window_size while self.frame_timestamps and now - self.frame_timestamps[0] > self.window_size: self.frame_timestamps.pop(0) def get_fps(self): if not self.frame_timestamps: return 0.0 time_span = self.frame_timestamps[-1] - self.frame_timestamps[0] if time_span <= 0: return len(self.frame_timestamps) return len(self.frame_timestamps) / time_span def should_print(self): now = time.time() if now - self.last_print_time >= self.window_size: self.last_print_time = now return True return False class InferencerProcess(multiprocessing.Process): def __init__(self, inference_queue, result_queue): super().__init__() self.inference_queue = inference_queue # 从推理队列获取数据 self.result_queue = result_queue # 发送结果到结果队列 self.running = True self.lpd = None self.lnr = None self.tensor = None def init_model(self): """初始化推理模型""" import torch pid = os.getpid() print(f"[推理进程-{pid}] 初始化模型...") if torch.cuda.is_available(): torch.cuda.init() torch.cuda.set_device(0) print(f"[推理进程-{pid}] CUDA初始化成功,设备: {torch.cuda.get_device_name(0)}") else: raise RuntimeError("CUDA not available in worker process") from src.alpr.core.model_loader import Predictor, get_model from src.alpr.core.LicensePlateProcessor import project_root lpd_classes = ("LicensePlate",) lnr_classes = ("0","1","2","3","4","5","6","7","8","9", "A","B","C","D","E","F","G","H","J","K", "L","M","N","P","Q","R","S","T","U","V", "W","X","Y","Z") lpd_model = get_model(project_root/"models/yolox_lpd_s_20240201.pth", num_classes=len(lpd_classes)) lnr_model = get_model(project_root/"models/yolox_lnr_s_20240201.pth", num_classes=len(lnr_classes)) self.lpd = Predictor(lpd_model, obj_labels=lpd_classes, confthre=0.01, img_size=(544, 960)) self.lnr = Predictor(lnr_model, lnr_classes, confthre=0.7, img_size=(320, 640)) print(f"[推理进程-{pid}] 模型初始化完成") # self.tensor = torch.as_tensor(np.ones((3, 1080, 1920), dtype=np.uint8), device='cuda') def run(self): pid = os.getpid() print(f"[推理进程-{pid}] 启动成功") try: self.init_model() while self.running: try: # 从推理队列获取数据 data = self.inference_queue.get(block=False) if not data: continue tensor, rtsp_id, request_id = data #tensor = self.tensor # 执行推理 try: out, _, _ = self.lpd.inference(tensor) out, T3, T4 = self.lnr.inference(tensor) #out, T3, T4 = [], 0, 0 # 将检测结果转换为仅包含基本类型的字典 detections = [] for det in out: # 确保所有值都是Python基本类型 detection = { 'label': str(det['label']), 'confidence': float(det['confidence']), 'x1': float(det['bbox'][0]), 'y1': float(det['bbox'][1]), 'x2': float(det['bbox'][2]), 'y2': float(det['bbox'][3]) } detections.append(detection) # 推理成功,将结果放入结果队列 (仅包含可序列化对象) res = { 'status': 'success', 'data': { 'detections': detections, 'rtsp_id': rtsp_id, 'request_id': request_id, 'timing': { 't3': float(T3) if T3 is not None else 0, 't4': float(T4) if T4 is not None else 0 } } } self.result_queue.put_nowait(res) except Exception as e: error_msg = f"推理失败: {str(e)}" print(f"[推理进程-{pid}] {error_msg}") self.result_queue.put_nowait({ 'status': 'error', 'data': { 'message': error_msg, 'rtsp_id': rtsp_id, 'request_id': request_id } }) except multiprocessing.queues.Empty: time.sleep(0.001) except Exception as e: print(f"[推理进程-{pid}] 异常: {str(e)}") except Exception as e: print(f"[推理进程-{pid}] 初始化失败: {str(e)}") print(f"[推理进程-{pid}] 已停止") class DecodeProcess(multiprocessing.Process): def __init__(self, decode_queue, inference_queue, result_queue): super().__init__() self.decode_queue = decode_queue # 接收h264数据 self.inference_queue = inference_queue # 发送解码结果 self.result_queue = result_queue # 发送错误信息 self.running = True self.fps_counter = FPSCounter() from av_decoder import AVDecoder self.decoder = AVDecoder() print(f"[Decode进程-{os.getpid()}] 初始化完成") def run(self): pid = os.getpid() print(f"[Decode进程-{pid}] 启动成功") while self.running: try: # 从队列获取h264数据 data = self.decode_queue.get(block=False) if not data: continue h264_data, rtsp_id, request_id = data tensor, t2, t5 = self.decoder.decode(h264_data, rtsp_id) if tensor is None: error_msg = "Failed to decode H264 to tensor" print(f"[Decode进程-{pid}] {error_msg}, request_id={request_id}") self.result_queue.put_nowait({ 'status': 'error', 'data': { 'message': error_msg, 'rtsp_id': rtsp_id, 'request_id': request_id } }) continue if self.fps_counter.should_print(): print(f"Decoder FPS: {self.fps_counter.get_fps():.2f}") # 解码成功,发送到推理队列 try: self.inference_queue.put_nowait((tensor, rtsp_id, request_id)) self.fps_counter.add_frame() except multiprocessing.queues.Full: self.result_queue.put_nowait({ 'status': 'error', 'data': { 'message': '推理队列已满', 'rtsp_id': rtsp_id, 'request_id': request_id } }) print(f'Inference 隊列已滿') self.fps_counter.add_frame() except multiprocessing.queues.Empty: time.sleep(0.001) # 避免忙等待 except Exception as e: print(f"[Decode进程-{pid}] 异常: {str(e)}") break print(f"[Decode进程-{pid}] 已停止") class FinalizerProcess(multiprocessing.Process): def __init__(self, result_queue, response_queue): super().__init__() self.result_queue = result_queue # 从推理队列获取结果 self.response_queue = response_queue # 将处理好的结果发送回主进程 self.running = True def run(self): pid = os.getpid() print(f"[Finalizer进程-{pid}] 启动成功") while self.running: try: # 从结果队列获取数据 result_dict = self.result_queue.get(block=False) #print("RES:", result_dict) if result_dict: # 将结果发送回主进程 self.response_queue.put(result_dict) except multiprocessing.queues.Empty: continue except Exception as e: print(f"[Finalizer进程-{pid}] 异常: {str(e)}") break print(f"[Finalizer进程-{pid}] 已停止") class ResponseHandler: """在主进程中处理响应的类""" def __init__(self): self.pending_requests = {} # request_id -> (context, response_future) self.lock = threading.Lock() def register_request(self, request_id, context, response_future): """注册新请求""" with self.lock: self.pending_requests[request_id] = (context, response_future) def process_response(self, response_dict): """处理从Finalizer进程返回的响应""" try: data = response_dict['data'] request_id = data['request_id'] with self.lock: if request_id not in self.pending_requests: print(f"请求ID {request_id} 未找到上下文") return context, response_future = self.pending_requests.pop(request_id) # 当前全部返回 Empty Response response_future.set_result(video_service_pb2.DecodeAndInferResponse()) return if response_dict['status'] == 'success': # 构造gRPC响应 detections = [] for det in data['detections']: proto_det = video_service_pb2.Detection( label=det['label'], confidence=det['confidence'], x1=det['x1'], y1=det['y1'], x2=det['x2'], y2=det['y2'] ) detections.append(proto_det) response = video_service_pb2.DecodeAndInferResponse(detections=detections) response_future.set_result(response) else: # 设置错误状态 context.set_code(grpc.StatusCode.INTERNAL) context.set_details(data['message']) response_future.set_result(video_service_pb2.DecodeAndInferResponse()) except Exception as e: print(f"响应处理异常: {str(e)}") class DecodeAndInferService(video_service_pb2_grpc.DecodeAndInferServiceServicer): decode_frame = 0 start_time = None def __init__(self, decode_queue: multiprocessing.Queue, result_queue, response_handler): self.decode_queue = decode_queue self.result_queue = result_queue self.response_handler = response_handler self.request_counter = 0 self.counter_lock = threading.Lock() self.fps_counter = FPSCounter() # 在主进程中初始化解码器 from h264_reassembler import H264Reassembler self.reassembler = H264Reassembler() print("[主进程] 解码器初始化完成") async def DecodeAndInfer(self, request, context): # 生成唯一请求ID with self.counter_lock: self.request_counter += 1 request_id = self.request_counter if DecodeAndInferService.start_time == None: DecodeAndInferService.start_time = time.time() DecodeAndInferService.decode_frame += 1 # 创建Future对象 response_future = asyncio.Future() # 注册请求 self.response_handler.register_request(request_id, context, response_future) try: # 提取需要的数据,创建可序列化的字典 h264_data = self.reassembler.reassemble(request.packets, request.rtsp_id) if h264_data is not None: self.decode_queue.put_nowait((h264_data, request.rtsp_id, request_id)) else: self.result_queue.put_nowait({ 'status': 'error', 'data': { 'message': 'cant convert rtp packets to h264', 'rtsp_id': request.rtsp_id, 'request_id': request_id } }) except multiprocessing.queues.Full: self.result_queue.put_nowait({ 'status': 'error', 'data': { 'message': 'decode队列已满', 'rtsp_id': request.rtsp_id, 'request_id': request_id } }) print(f'Decode 隊列已滿') except Exception as e: context.set_code(grpc.StatusCode.INTERNAL) context.set_details(f'处理请求失败: {str(e)}') return video_service_pb2.DecodeAndInferResponse() finally: # 等待结果 result = await response_future print(f"D&F Service FPS: {DecodeAndInferService.decode_frame / (time.time() - DecodeAndInferService.start_time)}") return result async def response_worker(response_queue, response_handler): """响应处理工作线程,在主进程中运行""" while True: try: response_dict = response_queue.get(block=False) response_handler.process_response(response_dict) except multiprocessing.queues.Empty: await asyncio.sleep(0.001) except Exception as e: print(f"响应处理线程异常: {str(e)}") async def serve(port, decode_queue, result_queue, response_queue): """启动gRPC服务""" # 创建响应处理器 response_handler = ResponseHandler() # 启动响应处理工作线程 asyncio.create_task(response_worker(response_queue, response_handler)) server = aio.server() service = DecodeAndInferService(decode_queue, result_queue, response_handler) video_service_pb2_grpc.add_DecodeAndInferServiceServicer_to_server(service, server) server.add_insecure_port(f'[::]:{port}') print(f"[gRPC服务] 启动成功,监听端口 {port}") await server.start() await server.wait_for_termination() def main(): parser = argparse.ArgumentParser(description='视频解码推理服务') parser.add_argument('--port', type=int, default=50151, help='gRPC服务端口') args = parser.parse_args() # 创建进程间通信队列 decode_queue = multiprocessing.Queue(maxsize=50) # 主进程→Decode进程 inference_queue = multiprocessing.Queue(maxsize=50) # Decode进程→Inference进程 result_queue = multiprocessing.Queue(maxsize=50) # Decode进程/Inference进程→Finalizer response_queue = multiprocessing.Queue(maxsize=50) # Finalizer→主进程 # 启动工作进程 decoder = DecodeProcess(decode_queue, inference_queue, result_queue) inferencer = InferencerProcess(inference_queue, result_queue) finalizer = FinalizerProcess(result_queue, response_queue) decoder.start() inferencer.start() finalizer.start() print(f"[主进程] 启动gRPC服务,端口 {args.port}") try: # 启动gRPC服务 (主进程同时负责解码) asyncio.run(serve(args.port, decode_queue, result_queue, response_queue)) except KeyboardInterrupt: print("\n[主进程] 收到停止信号") # 停止工作进程 inferencer.running = False finalizer.running = False # 等待进程结束 inferencer.join() finalizer.join() print("[主进程] 所有进程已停止") if __name__ == '__main__': # 确保使用spawn启动方法 multiprocessing.set_start_method('spawn', force=True) main() 修改代码,让各自组件都可以以其全速进行处理
08-12
原封不动增加注释:@ns.route('/train') class TrainingResource(Resource): @ns.doc('训练模型') @ns.expect(train_request) @ns.response(201, '模型训练成功', train_response) @ns.response(400, '请求参数错误', error_response) @ns.response(500, '服务器内部错误', error_response) def post(self): """训练模型接口""" try: parsed_data = json.loads(request.data.decode('utf-8')) recipeDict = {} for key, value in eval(parsed_data["recipeDict"].replace("null","None")).items(): # recipeDict[key]=pd.read_json(value, orient='records') recipeDict[key] = pd.DataFrame.from_dict(value, orient='index').T spec = pd.DataFrame.from_dict(parsed_data["spec"], orient='index').T type = parsed_data["type"] # data = request.json start_time = time.time() # import pdb;pdb.set_trace() model_id = train_model( recipeDict=recipeDict, spec=spec, type=type ) training_time = time.time() - start_time return { 'model_id': model_id, 'metrics': 0.8, 'training_time': training_time, 'message': 'Model training succeed.' }, 200 except ValueError as e: print(e) logging.exception("Exception occurred") return { 'message': str(e), 'error_code': 400 }, 400 except Exception as e: print(e) logging.exception("Exception occurred") return { 'message': f'Server internal error: {str(e)}', 'error_code': 500 }, 500 @ns.route('/inference') class InferenceResource(Resource): @ns.doc('模型推理') @ns.expect(train_request) @ns.response(201, '模型训练成功', train_response) @ns.response(400, '请求参数错误', error_response) @ns.response(500, '服务器内部错误', error_response) def post(self): """训练模型接口""" try: # parsed_data = parse_qs(request.data.decode('utf-8')) parsed_data = json.loads(request.data.decode('utf-8')) # recipe_id=pd.DataFrame.from_dict(parsed_data["recipe_id"], orient='index').T recipeDict = {} for key, value in eval(parsed_data["recipeDict"].replace("null","None")).items(): # recipeDict[key]=pd.read_json(value, orient='records') recipeDict[key] = pd.DataFrame.from_dict(value, orient='index').T recipe_id = recipeDict[parsed_data["recipe_id"]] recipe_name=parsed_data["recipe_id"] model_id = parsed_data["model_id"] # if 'inear' in model_id: # model_id='l'+model_id start_time = time.time() sepc = model_inference( recipe_id=recipe_id, model_id=model_id, recipe_name=recipe_name ) training_time = time.time() - start_time # import pdb; # pdb.set_trace() return { 'spec': json.dumps(sepc.iloc[0].to_dict()), 'metrics': 0.7, 'training_time': training_time, 'message': 'Model training succeed.' }, 200 except ValueError as e: print(e) logging.exception("Exception occurred") return { 'message': str(e), 'error_code': 400 }, 400 except Exception as e: print(e) logging.exception("Exception occurred") return { 'message': f'Server internal error: {str(e)}', 'error_code': 500 }, 500 def get_key_index(target_key, dictionary): for index, key in enumerate(dictionary.keys()): if key == target_key: return index return -1
最新发布
08-29
原封不动增加注释:@ns.route('/tune') class ProcessParamsOptimizationResource(Resource): @ns.doc('参数调优') @ns.expect(optimize_process_params_request) @ns.response(200, '参数调优成功', optimize_process_params_response) @ns.response(400, '请求参数错误', error_response) @ns.response(500, '服务器内部错误', error_response) def post(self): """调优接口""" try: # data = request.json # parsed_data = parse_qs(request.data.decode('utf-8')) # recipe_id=pd.read_json(parsed_data["recipe_id"][0], orient='records') parsed_data = json.loads(request.data.decode('utf-8')) model_id = parsed_data["model_id"] if 'inear' in model_id: model_id=model_id start_time = time.time() recipeDict = {} for key, value in eval(parsed_data["recipeDict"].replace("null","None")).items(): # recipeDict[key]=pd.read_json(value, orient='records') recipeDict[key] = pd.DataFrame.from_dict(value, orient='index').T index = get_key_index(parsed_data["recipe_id"], recipeDict) recipe_id = recipeDict[parsed_data["recipe_id"]] # import pdb; # pdb.set_trace() # spec=pd.read_json(parsed_data["spec"], orient='index').T spec = pd.DataFrame.from_dict(parsed_data["spec"], orient='index').T # parsed_data = parse_qs(request.data.decode('utf-8')) # recipe_id=pd.read_json(parsed_data["recipe_id"][0], orient='records') # model_id = parsed_data["model_id"][0] # start_time = time.time() # recipeDict={} # for key,value in eval(parsed_data["recipeDict"][0]).items(): # recipeDict[key]=pd.read_json(value, orient='records') # spec=pd.read_json(parsed_data["spec"][0], orient='records') parsed_data["spec"] target_spec = parsed_data["target_spec"] # 定义权重 weights =parsed_data["weights"] best_param_n_spec_dict, non_zero_indices,step_order,parameter_order,importance = optimize_process_params( recipeDict=recipeDict, spec=spec, seed_id=index, seed=recipe_id, target_spec=target_spec, weights=weights, model_id=model_id ) optimization_time = time.time() - start_time print(best_param_n_spec_dict) data = [] for b in best_param_n_spec_dict: d = {} for k, v in b.items(): print(type(v)) if isinstance(v, np.ndarray): v: np.ndarray d[k] = v.tolist() elif isinstance(v, pd.DataFrame): d[k] = v.to_json() elif isinstance(v, pd.Series): d[k] = v.to_dict() elif isinstance(v, float): d[k] = v data.append(d) # import pdb; # pdb.set_trace() # print(str(best_param_n_spec_dict)) # print(str(non_zero_indices)) return { 'best_param_n_spec_dict': str(best_param_n_spec_dict), 'columns': importance, 'optimization_time': optimization_time, 'non_zero_indices': str(non_zero_indices), 'data':data, 'message': 'Success.' }, 200 except ValueError as e: print(e) logging.exception("Exception occurred") return { 'message': str(e), 'error_code': 400 }, 400 except Exception as e: print(e) logging.exception("Exception occurred") return { 'message': f'Server internal error: {str(e)}', 'error_code': 500 }, 500
08-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值