window下Nginx+php不支持并发,导致curl请求卡死

本文描述了在本地配置多个域名时,使用PHP的curl请求出现卡死的情况及原因,详细解释了在Windows环境下配置nginx+php环境中不支持并发的问题,并提供了通过配置不同端口来解决该问题的方法。

1、问题描述:

在本地配置多个域名时,使用php的curl请求出现卡死情况。具体为:一个域名发起请求刚刚超时后,另外一个域名接收到响应,出现卡死情况。curl超时时间为:curl_setopt($http, CURLOPT_TIMEOUT, 10);

发送请求的域名:[2019-08-01 15:24:21] getUserId
接收请求的域名:[2019-08-01 15:24:31] lumen.INFO:[api接口getUserId]

由上可以看出,刚刚好一个请求结束,在处理其他请求。

2、具体原因:在window环境下配置的nginx+php环境时,由于不支持并发,也就是,当本地配置了多个域名,并且同时指向你本地服务请求的时候,就不支持了。

3、解决方案:

我这里有两个服务,所以分别配置成不同的端口号如,然后保存重启 nginx
fastcgi_pass = 127.0.0.1:9000
fastcgi_pass  = 127.0.0.1:9001

你的php目录/php-cgi.exe -b 127.0.0.1:9000 -c 你的php目录/php.ini
你的php目录/php-cgi.exe -b 127.0.0.1:9001 -c 你的php目录/php.ini

这样就完美解决了。

#!/bin/env python # 必须写在第一行 # -*- coding: utf-8 -*- ################################################# # LOAD_MODE__ import os import re import sys from PyQt5.QtCore import Qt, QRegExp, QEvent, QThread, QTimer, QObject, pyqtSignal from PyQt5.QtWidgets import QWidget, QApplication, QMessageBox, QDialog # from ui import param from PyQt5.QtGui import QRegExpValidator from messageBox import messageBox from collections import defaultdict from py39COM import Gateway, InCAM from py39Tools import TableWidget from ICO import ICO from ICNET import ICNET from EqHelper import EqHelper # from fastmcp import Api, Resource # import tkinter as tk import requests import threading from Ui_interface import Ui_Dialog as inerfaceui from Ui_job_input import Ui_ChildWindow as job_input_ui from Ui_get_layer import Ui_ChildWindow2 as get_layer_ui from Ui_draw_circle import Ui_ChildWindow3 as draw_circle_ui import subprocess import psutil import time import netifaces import json from pypinyin import lazy_pinyin from fastapi import FastAPI import uvicorn # from img import apprcc_rc # from pprint import pprint # from sublib import # print('apprcc_rc.rcc_version : %s' % apprcc_rc.rcc_version) #第一步:在终端运行python interface.py #第二步:点击按钮确认GUI功能 #第三步:保持 interface.py 运行状态,在另一个终端中测试:curl http://127.0.0.1:8000,会返回:{"message": "Hello, World!"}类似信息 ##测试调用curl -X POST http://127.0.0.1:8000/api/open_incam,返回json信息。对其他接口同样进行测试,如:curl -X POST http://127.0.0.1:8000/api/open_job # #第四步:运行该代码,在浏览器输入:http://127.0.0.1:8000/docs # MODE_END__ def get_pinyin(chinese): if not chinese: return '' str = chinese new_str = str[0:] # print(new_str) new_str1 =''.join(lazy_pinyin(new_str)) # print(new_str1) return new_str1 def GetUserInfo(mode=None): ''' 从指定URL获取主机信息(JSON格式) 返回值:成功返回JSON对象,失败返回None ''' getHtml = 'http://sheet.scc.com/gethosts/format/json' resp = requests.get(getHtml, timeout=60) if resp.status_code == 200: json_obj = json.loads(resp.content.decode()) return json_obj else: return None def get_local_ip(): """ 获取本机 IP 地址,优先返回 10.x.x.x,其次 192.168.x.x """ ip_list = [] for interface in netifaces.interfaces(): addrs = netifaces.ifaddresses(interface) if netifaces.AF_INET in addrs: for addr_info in addrs[netifaces.AF_INET]: ip = addr_info['addr'] if ip.startswith('10.'): return ip # 立即返回第一个10.x地址 ip_list.append(ip) #找到的是192开头的ip地址则转换成10开头的ip if ip.startswith('192.168.200.'): parts = ip.split('.') new_ip = f'10.61.26.{parts[3]}' return new_ip ip_list.append(ip) # 如果没有10.x地址,返回第一个192.x地址 for ip in ip_list: if ip.startswith('192.'): return ip # 都没有则返回第一个找到的IP return ip_list[0] if ip_list else "127.0.0.1" def get_username(): try: local_ip = get_local_ip() # print(f"Local IP address: {local_ip}") user_info = GetUserInfo(local_ip) if not user_info or not isinstance(user_info, list): print("用户信息为空或格式错误。") return None res= [x for x in user_info if x['ip_address'] == local_ip] if len(res) == 0: return None username = res[0]['user'] # print(f"准备调用 SubCenterGetUserInfo,传入 username: {username}") englishname = get_pinyin(username) return englishname except Exception as e: print(f"获取用户信息失败: {e}") return None #获取当前打开的窗口的进程 def get_window_processes(): try: # 使用wmctl获取窗口列表 output = subprocess.check_output(['wmctrl', '-lp']).decode('utf-8') window_pids = [] for line in output.splitlines(): parts = line.split() if len(parts) >= 3: window_pids.append(int(parts[2])) return list(set(window_pids)) # 去重 except FileNotFoundError: print("请先安装wmctrl: sudo apt install wmctrl") return [] # 判断incam是否在运行 def is_process_running(): """ 判断InCAMPro进程是否正在运行 返回: bool: True表示进程正在运行,False表示未运行 """ window_pids = get_window_processes() if not window_pids: print("无法获取窗口进程信息") return False for proc in psutil.process_iter(['pid', 'name']): if proc.info['pid'] in window_pids and proc.info['name'].lower() == 'incampro': return True return False # 获取incam的pid def get_incampro_pid(): """ 获取InCAMPro进程的PID 返回: int/None: 返回进程PID(如果找到),否则返回None """ window_pids = get_window_processes() if not window_pids: print("无法获取窗口进程信息") return None for proc in psutil.process_iter(['pid', 'name']): if proc.info['pid'] in window_pids and proc.info['name'].lower() == 'incampro': return proc.info['pid'] # 返回找到的PID return None # 没有找到则返回None # FUNCTION__ class Child_window(QDialog): """ 料号输入子窗口 """ def __init__(self, parent=None): super().__init__(parent) self.child_ui1 = job_input_ui() self.child_ui1.setupUi(self) # 添加确认按钮信号连接 self.child_ui1.confirm_btn.clicked.connect(self.confirm_input) self.material_number = None # 存储输入的料号 def get_material_number(self): return self.child_ui1.input_job.text().strip() def confirm_input(self): """验证输入并关闭窗口""" if self.get_material_number(): self.accept() # 关闭对话框并返回QDialog.Accepted else: QMessageBox.warning(self, "错误", "请输入有效料号") class ChildWindow2(QDialog): """层名选择对话框""" def __init__(self, layer_list, parent=None): super().__init__(parent) self.child_ui2 = get_layer_ui() self.child_ui2.setupUi(self, layer_list) # 初始化下拉框 self.child_ui2.get_layer.addItems(layer_list) if layer_list: self.child_ui2.get_layer.setCurrentIndex(0) # 连接信号 self.child_ui2.btn_ok.clicked.connect(self.accept) self.child_ui2.btn_ok.clicked.connect(self.store_selection) self.selected_layer = None def store_selection(self): """存储选择的层名""" self.selected_layer = self.child_ui2.get_layer.currentText() def get_selected_layer(self): """获取选择的层名""" return self.selected_layer class ChildWindow3(QDialog): """ 画圆子窗口 """ def __init__(self, parent=None): super().__init__(parent) self.child_ui3 = draw_circle_ui() self.child_ui3.setupUi(self) # 添加确认按钮信号连接 self.child_ui3.sure_btn.clicked.connect(self.accept) self.value = None def get_circle_data(self): """获取输入的圆参数""" try: x = float(self.child_ui3.x_input.text()) y = float(self.child_ui3.y_input.text()) sym = self.child_ui3.sym_input.text() # 保持为字符串 if not sym: # 检查是否为空 return None return (x, y, sym) except ValueError: return None class ComTestQT(QWidget): """ PYQT界面实现对应按钮操作incam动作 """ def __init__(self): # def __init__(self, pid=None, JOB=None, STEP=None): super(ComTestQT, self).__init__() self.main_ui = inerfaceui() self.main_ui.setupUi(self) self.setWindowFlags(Qt.WindowStaysOnTopHint) self.JOB = os.environ.get('JOB', None) # print(f"JOB: {self.JOB}") # print("111111111111111111111111111111") self.STEP = os.environ.get('STEP', None) # --启动pycharm.sh时,里面有export INCAM_DEBUG=yes设置此环境变量 INCAM_DEBUG = os.getenv('INCAM_DEBUG', None) # 接口定义 # if INCAM_DEBUG == 'yes': # 通过genesis gateway命令连结pid进行会话,不用在genesis环境下运行,直接用gateway的方式,可在pycharm环境下直接debug self.incam = Gateway() # 方法genesis_connect通过查询log-genesis文件获取的料号名 # self.JOB = self.incam.job_name # self.STEP = self.incam.step_name # self.pid = self.incam.pid # else: # self.incam = InCAM() # self.pid = os.getpid() self.ico = ICO(incam=self.incam) # self.icNet = ICNET(incam=self.incam) # # self.eqHelper = EqHelper(self.incam, self.JOB, self.STEP) # print(f"没有debug:{self.JOB}") # self.jobName = self.ico.SimplifyJobName(jobName=self.JOB) # self.dbSite = self.ico.GetDBSite(JOB=self.JOB) # self.SITE = self.ico.GetSite(JOB=self.JOB) # layerMatrix = self.ico.GetLayerMatrix() # self.incam.COM("get_user_group") # self.uGroup = self.incam.COMANS # self.incam.COM('get_user_name') # self.userName = self.incam.COMANS # self.incam.gateway_connect() self.child_window = None self.child_window2 = None self.child_window3 = None self.slot_func() # 全局引用自己,供 FastAPI 使用 global qt_app_instance qt_app_instance = self def slot_func(self): """ 统一定义槽函数 :return: """ self.main_ui.open_incam.clicked.connect(self.start_incam) self.main_ui.open_job.clicked.connect(self.show_child_window) self.main_ui.get_layername.clicked.connect(self.show_layer_dialog) self.main_ui.draw_circle.clicked.connect(self.show_draw_circle_dialog) # 连接信号到实际方法 api_signals.open_incam_signal.connect(self.start_incam) api_signals.open_job_signal.connect(self.show_child_window) api_signals.get_layername_signal.connect(self.show_layer_dialog) api_signals.draw_circle_signal.connect(self.show_draw_circle_dialog) ########运行incam程序###### def start_incam(self): """ 尝试通过终端命令启动 incam 或 pro """ if is_process_running(): print("已有InCAMPro进程正在运行,无法再次启动") # messageBox("Incam 已在运行") return else: try: self.file_path = "/home/genesis/.incam/login" self.file_path_enc = "/home/genesis/.incam/login.enc" account = get_username()#"songwenhua"#self.inputNewAccount.text().strip() password = "scc123456"#self.inputNewPassword.text().strip() if os.path.exists(self.file_path_enc): os.remove(self.file_path_enc) with open(self.file_path, "w", encoding="utf-8") as f: f.writelines('\n'.join((account, password))) home = os.path.expanduser("~") # 获取家目录路径 # subprocess.Popen(['gnome-terminal', '--working-directory', home, '--', 'bash', '-ic', 'incam; exec bash']) subprocess.Popen(['gnome-terminal', '--working-directory', home, '--', 'bash', '-ic', 'pro; exec bash']) print("Incam 已作为后台进程启动") # while not is_process_running(): time.sleep(10) if os.path.exists(self.file_path): os.remove(self.file_path) except FileNotFoundError: print("'gnome-terminal' 未找到,请安装它:sudo apt install gnome-terminal") except Exception as e: print("启动 incam 时发生异常:", str(e)) def show_child_window(self): """显示子窗口并等待输入""" # 重置子窗口状态 if self.child_window is None: self.child_window = Child_window(self) self.child_window.child_ui1.input_job.clear() if self.child_window.exec_() == QDialog.Accepted: short_name = self.child_window.get_material_number() self.open_JOB(short_name) def ensure_incam_ready(self): """确保 incam 和 ico 都已准备就绪""" # if self.incam is None: self.incam = Gateway() self.ico = ICO(incam=self.incam) # else: # pid = get_incampro_pid() # print("22222222222222222222222") if not hasattr(self.incam, 'pid'): print("44444") # if pid is None: if not self.incam.pid: print("pid is None") return False # if self.ico is None: # self.ico = ICO(incam=self.incam) print("kkkkkkkkk") return True def open_JOB(self, short_name=None): """ 根据料号简称打开对应的全称JOB 参数: material_number (str): 要打开的料号,如果为None则使用当前JOB 返回: bool: True表示打开成功,False表示失败 """ try: # 1. 检查InCAMPro进程 pid = get_incampro_pid() if pid is None: QMessageBox.warning(self, "警告", "请先启动InCAMPro") return False # 初始化Gateway连接 # 等待 Gateway 真正准备好 print(f"pid11: {pid}") if not self.ensure_incam_ready(): print(f"pid: {pid}") QMessageBox.warning(self, "警告", "Gateway连接失败") return False # ---------------------------------------------- # print("111111111111111111111111111111111111111") # print(f"pid: {pid}") # # if not self.incam.pid: # # self.incam.connect(pid) # print("self.incam.pid:", self.incam.pid) # print("nnnnn: ",hasattr(self.incam, 'pid')) # # self.incam.pid = get_incampro_pid() # if not hasattr(self.incam, 'pid') or not self.incam.pid: # QMessageBox.warning(self, "警告", "Gateway连接失败") # return False # 获取JOB列表并验证料号 job_list = self.ico.GetJOBlist() if not job_list: QMessageBox.warning(self, "警告", "没有可用的JOB列表") return False # 查找匹配的全称料号 full_name = None for JOB in job_list: simplified = self.ico.SimplifyJobName(jobName=JOB) if simplified == short_name: full_name = JOB break if not full_name: QMessageBox.warning(self, "错误", f"未找到匹配全称的料号: {short_name}") return False # 打开全称料号 self.incam.COM(f'open_job,job={full_name},open_win=yes') self.JOB = full_name if self.ico.isJobOpen(full_name): QMessageBox.information(self, "成功", f"已打开料号: {full_name}") # return True else: QMessageBox.warning(self, "错误", f"打开料号失败: {full_name}") # return False except Exception as e: QMessageBox.critical(self, "异常", f"处理料号时出错: {str(e)}") # return False def show_layer_dialog(self): """显示层名选择对话框""" try: # 验证前置条件 # jobName=self.JOB print(f"JOB value before check: {self.JOB}")#已经得到了准确的job名称 if not self.check_preconditions(): return # 获取层名列表 # print(f"JOB v: {self.JOB}") layer_list = self.ico.GetLayerList() if not layer_list: QMessageBox.warning(self, "警告", "没有可用的Layer列表") return # 创建并显示对话框 dialog2 = ChildWindow2(layer_list, self) if dialog2.exec_() == QDialog.Accepted: selected_layer = dialog2.get_selected_layer() self.handle_selected_layer(selected_layer) except Exception as e: QMessageBox.critical(self, "错误", f"操作失败: {str(e)}") def check_preconditions(self): """检查必要前提条件""" if get_incampro_pid() is None: QMessageBox.warning(self, "警告", "请先启动InCAMPro") return False # 尝试获取当前激活的JOB try: if self.incam.job_name: self.JOB = self.incam.job_name # print(f"从incam获取的JOB: {self.JOB}") QMessageBox.information(self, "成功", f"从incam获取的JOB: {self.JOB}") except Exception as e: # print(f"获取incam job_name失败: {str(e)}") QMessageBox.warning(f"获取incam job_name失败: {str(e)}") # 检查JOB是否有效 if not self.JOB: QMessageBox.warning(self, "警告", "请打开JOB后再操作") return False # 尝试获取layer列表验证JOB有效性 try: self.ico.JOB= self.JOB layer_list = self.ico.GetLayerList() # print(f"获取到的层列表: {layer_list}") if not layer_list: QMessageBox.warning(self, "警告", "获取到的层列表为空") return False return True except Exception as e: QMessageBox.warning(self, "警告", f"获取层列表失败: {str(e)}") return False def handle_selected_layer(self, layer_name): """处理选择的层名""" print(f"选择的层名: {layer_name}") self.LAYER = layer_name QMessageBox.information(self, "成功", f"已选择层名: {layer_name}") def show_draw_circle_dialog(self): """显示画圆参数对话框""" if not self.check_preconditions(): return if not hasattr(self, 'LAYER') or not self.LAYER: QMessageBox.warning(self, "警告", "请先选择层") return dialog3 = ChildWindow3(self) if dialog3.exec_() == QDialog.Accepted: params = dialog3.get_circle_data() # print(f"获取的参数: {params}") if params: self.draw_circle_on_layer(*params) else: QMessageBox.warning(self, "警告", "请输入有效的数字参数") def draw_circle_on_layer(self, center_x, center_y, symbol): """在指定层上画圆""" try: self.ico.ClearAll() layer_name=self.LAYER self.ico.DispWork(layer=layer_name) self.ico.AddPad( x = center_x, y = center_y, sym = symbol ) self.ico.ClearLayer() QMessageBox.information(self, "成功", f"已在层 {self.LAYER} 上绘制圆形") except Exception as e: QMessageBox.critical(self, "错误", f"画圆时出错: {str(e)}") ########## FastAPI 部分 ########### class ApiSignalEmitter(QObject): open_incam_signal = pyqtSignal() open_job_signal = pyqtSignal() get_layername_signal = pyqtSignal() draw_circle_signal = pyqtSignal() api_signals = ApiSignalEmitter() # app = FastAPI(title="InCAM Remote Control API", description="通过HTTP控制InCAM自动化任务") app = FastAPI(title="InCAM 控制 API", version="1.0") @app.post("/api/open_incam") async def api_open_incam(): # qt_app_instance.start_incam() # 不再直接调用 myapp.open_job() # 而是发送信号给主线程处理 api_signals.open_incam_signal.emit() return {"status": "success", "action": "open_incam", "message": "InCAM已启动"} @app.post("/api/open_job") async def api_open_job(): # qt_app_instance.show_child_window() api_signals.open_job_signal.emit() return {"status": "success", "action": "open_job", "message": "Job窗口已打开"} @app.post("/api/get_layername") async def api_get_layername(): # qt_app_instance.show_layer_dialog() api_signals.get_layername_signal.emit() return {"status": "success", "action": "get_layername", "message": "层名获取成功"} @app.post("/api/draw_circle") async def api_draw_circle(): # qt_app_instance.show_draw_circle_dialog() api_signals.draw_circle_signal.emit() return {"status": "success", "action": "draw_circle", "message": "圆圈绘制完成"} @app.get("/") async def root(): return { "message": "InCAM 控制 API 运行中", "endpoints": [ "/api/open_incam", "/api/open_job", "/api/get_layername", "/api/draw_circle" ], "method": "POST" } # @app.get("/") # async def root(): # if qt_app_instance is None: # return {"status": "error", "message": "Qt app not initialized"} # return { # "status": "running", # "service": "InCAM Remote Control API", # "api_docs": "/docs", # "available_endpoints": [ # "/api/open_incam", # "/api/open_job", # "/api/get_layername", # "/api/draw_circle" # ] # } def run_fastapi(): """在后台线程运行 FastAPI""" uvicorn.run(app, host="127.0.0.1", port=8000, log_level="info") # def run_fastapi(): # """在后台线程运行 FastAPI""" # config = uvicorn.Config( # app=app, # host="127.0.0.1", # port=8000, # log_level="info", # lifespan="on" # 显式开启 lifespan 支持 # ) # server = uvicorn.Server(config) # server.run() qt_app_instance = None if __name__ == '__main__': qapp = QApplication(sys.argv) myapp = ComTestQT() myapp.show() print("PyQt5 GUI 已显示,将在1秒后启动 FastAPI...") # 在子线程中启动 FastAPI QTimer.singleShot( 1000, lambda: threading.Thread(target=run_fastapi, daemon=True).start() ) sys.exit(qapp.exec_()) # EXIT__ 以上是play.py的全部代码,并没有内联Uvicorn 的启动逻辑。
最新发布
10-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值