00 Preface

00 Preface

 

最近需要用到php,所以需要在极快的时间内熟悉php的语法特性和语言特性,仅以此文为开始。

 

目前的现实情况是:

1:有比较好的Java基础和Javascript基础。

2php基础较弱,需要系统的学习。

3:目标想在较短的时间内获得php知识的轮廓,有个整体的印象,能够应付正常工作。

 

使用书籍:

Programming PHP  3rd edition 

 

希望自己能坚持下来。

学习方式:

看书,主要以上面提到的那本书为主,E文。

练习,将书上的例子能够执行。

 

书籍加练习,另外会有语言的比较方式;通过语言特性的比较来学习,印象更深刻。

由于有一定的语言基础,想真正测试下自己对于学习新知识的能力。

 

以上。

要将代码中读取 `Validation Plan Preface` 模板的位置改成公共盘 `\\10.177.40.92\Department\Power - ODV - China\Lab\02_Project_Test_Leader\00_Project_Validation\Validation Plan & Report\01 Validation plan template`,将生成的 Excel 和 PPT 文件位置改为本地 `Downloads` 文件夹,可以对原代码中的相关部分进行修改。 #### 修改模板路径 在 `load_config` 函数中,修改 `TEMPLATE_PATHS` 列表,将公共盘路径添加进去。 ```python def load_config(): """加载配置文件""" config_path = "config.json" default_config = { "API": { "PROD_URL": "https://lims.se.com/STARLIMS11.prod/RESTServices.REST_API.Api_clab_testplan_v1.lims", "QUAL_URL": "https://qual.lims.se.com/STARLIMS11.qual/RESTServices.REST_API.Api_clab_testplan_v1.lims", "USER": "API_CN", "PASSWORD": "YLWT", "COOKIE": "ASP.NET_SessionId=nn30yrczlmvf31be5kvynwpq" }, "TEMPLATE_PATHS": [ r"\\10.177.40.92\Department\Power-ODV-China\Lab\02_Project_Test_Leader\00_Project_Validation\Validation Plan & Report\01 Validation plan template\Validation Plan Preface.xlsx", os.path.join("api_responses", "Validation Plan Preface.xlsx"), "Validation Plan Preface.xlsx", os.path.join(os.path.dirname(__file__), "Validation Plan Preface.xlsx") ], "MAX_PROCESS_ROWS": 10000, "PPT_MAX_DISPLAY_ITEMS": 10 } if os.path.exists(config_path): try: with open(config_path, 'r', encoding='utf-8') as f: config = json.load(f) for key, value in default_config.items(): if key not in config: config[key] = value return config except Exception as e: logger.warning(f"加载配置文件失败,使用默认配置: {e}") return default_config ``` #### 修改生成文件保存路径 在生成 Excel 和 PPT 文件的相关函数中,将保存路径改为本地 `Downloads` 文件夹。 ```python import os # 获取本地 Downloads 文件夹路径 downloads_folder = os.path.join(os.path.expanduser("~"), "Downloads") # 在 create_template_based_file 函数中修改保存路径 def create_template_based_file(df: pd.DataFrame, output_file: str, test_plan_id: str) -> bool: # ... 原代码 ... output_file = os.path.join(downloads_folder, os.path.basename(output_file)) try: # ... 原代码 ... workbook.save(output_file) logger.info(f"成功生成文件:{output_file}") return True except Exception as e: logger.error(f"生成文件失败:{str(e)}", exc_info=True) raise # 在 create_slides_from_ptl03 函数中修改保存路径 def create_slides_from_ptl03(): # ... 原代码 ... base_path = os.path.splitext(file_path)[0] slides_file = os.path.join(downloads_folder, f"{os.path.basename(base_path)}_Slides.pptx") if os.path.exists(slides_file): timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") slides_file = os.path.join(downloads_folder, f"{os.path.basename(base_path)}_Slides_{timestamp}.pptx") try: prs.save(slides_file) logger.info(f"幻灯片已保存到: {slides_file}") QMessageBox.information(None, "成功", f"幻灯片已保存:\n{slides_file}") ui.statusbar.showMessage(f"幻灯片已保存: {os.path.basename(slides_file)}") except PermissionError: temp_dir = os.path.join(os.environ.get('TEMP', '/tmp'), 'ptl_slides') os.makedirs(temp_dir, exist_ok=True) slides_file = os.path.join(temp_dir, os.path.basename(slides_file)) prs.save(slides_file) logger.warning(f"原路径无权限,已保存到临时目录: {slides_file}") QMessageBox.information(None, "保存成功", f"幻灯片已保存到:\n{slides_file}\n(原路径无写入权限)") # ... 原代码 ... ``` ###
是不是和这个有关 static void h2_init_con (request_st * const restrict h2r, connection * const restrict con) { h2con * const h2c = ck_calloc(1, sizeof(h2con)); con->hx = (hxcon *)h2c; con->fn = &http_dispatch[HTTP_VERSION_2]; con->reqbody_read = h2_recv_reqbody; con->read_idle_ts = log_monotonic_secs; con->keep_alive_idle = h2r->conf.max_keep_alive_idle; h2r->x.h2.rwin = 262144; /* h2 connection recv window (256k)*/ h2r->x.h2.swin = 65535; /* h2 connection send window */ h2r->x.h2.rwin_fudge = 0; /* settings sent from peer */ /* initial values */ h2c->s_header_table_size = 4096; /* SETTINGS_HEADER_TABLE_SIZE */ h2c->s_enable_push = 1; /* SETTINGS_ENABLE_PUSH */ h2c->s_max_concurrent_streams= ~0u; /* SETTINGS_MAX_CONCURRENT_STREAMS */ h2c->s_initial_window_size = 65536; /* SETTINGS_INITIAL_WINDOW_SIZE */ h2c->s_max_frame_size = 16384; /* SETTINGS_MAX_FRAME_SIZE */ h2c->s_max_header_list_size = ~0u; /* SETTINGS_MAX_HEADER_LIST_SIZE */ h2c->sent_settings = log_monotonic_secs;/*(send SETTINGS below)*/ lshpack_dec_init(&h2c->decoder); lshpack_enc_init(&h2c->encoder); lshpack_enc_use_hist(&h2c->encoder, 1); static const uint8_t h2settings[] = { /*(big-endian numbers)*/ /* SETTINGS */ 0x00, 0x00, 0x1e /* frame length */ /* 5 * (6 bytes per setting) */ ,H2_FTYPE_SETTINGS /* frame type */ ,0x00 /* frame flags */ ,0x00, 0x00, 0x00, 0x00 /* stream identifier */ ,0x00, H2_SETTINGS_MAX_CONCURRENT_STREAMS ,0x00, 0x00, 0x00, 0x08 /* 8 */ #if 0 /* ? explicitly disable dynamic table ? (and adjust frame length) */ /* If this is sent, must wait until peer sends SETTINGS with ACK * before disabling dynamic table in HPACK decoder */ /*(before calling lshpack_dec_set_max_capacity(&h2c->decoder, 0))*/ ,0x00, H2_SETTINGS_HEADER_TABLE_SIZE ,0x00, 0x00, 0x00, 0x00 /* 0 */ #endif #if 0 /* ? explicitly disable push ? (and adjust frame length) */ ,0x00, H2_SETTINGS_ENABLE_PUSH ,0x00, 0x00, 0x00, 0x00 /* 0 */ #endif ,0x00, H2_SETTINGS_INITIAL_WINDOW_SIZE /*(must match in h2_init_stream())*/ ,0x00, 0x01, 0x00, 0x00 /* 65536 *//*multiple of SETTINGS_MAX_FRAME_SIZE*/ #if 0 /* ? increase from default (16384) ? (and adjust frame length) */ ,0x00, H2_SETTINGS_MAX_FRAME_SIZE ,0x00, 0x00, 0x80, 0x00 /* 32768 */ #endif ,0x00, H2_SETTINGS_MAX_HEADER_LIST_SIZE ,0x00, 0x00, 0xFF, 0xFF /* 65535 */ ,0x00, H2_SETTINGS_ENABLE_CONNECT_PROTOCOL ,0x00, 0x00, 0x00, 0x01 /* 1 */ ,0x00, H2_SETTINGS_NO_RFC7540_PRIORITIES ,0x00, 0x00, 0x00, 0x01 /* 1 */ /* WINDOW_UPDATE */ ,0x00, 0x00, 0x04 /* frame length */ ,H2_FTYPE_WINDOW_UPDATE /* frame type */ ,0x00 /* frame flags */ ,0x00, 0x00, 0x00, 0x00 /* stream identifier */ ,0x00, 0x03, 0x00, 0x01 /* 196609 *//*(increase connection rwin to 256k)*/ }; chunkqueue_append_mem(con->write_queue, (const char *)h2settings, sizeof(h2settings)); if (!h2_recv_client_connection_preface(con)) { /*(alternatively, func ptr could be saved in an element in (h2con *))*/ con->plugin_ctx[0] = (void *)(uintptr_t)con->network_read; con->network_read = h2_read_client_connection_preface; /* note: no steps taken to reset con->network_read() on error * as con->network_read() is always set in connection_accepted() */ } buffer_string_prepare_copy(h2r->tmp_buf, 65535); }
10-08
<think>我们正在分析用户提供的lighttpd源码片段(h2_init_con函数),该函数用于初始化HTTP/2连接。用户之前遇到了上传大文件(超过64KB)失败的问题,错误信息为“cq->first is NULL”。现在用户怀疑这个HTTP/2初始化函数是否与问题有关。 让我们分析这个函数: 1. 函数`h2_init_con`用于初始化HTTP/2连接,设置一些默认参数和发送SETTINGS帧。 2. 在函数中,我们注意到与流(stream)和窗口大小(window size)相关的设置: - `h2r->x.h2.rwin = 262144;` // 连接接收窗口大小为256KB - `h2r->x.h2.swin = 65535;` // 连接发送窗口大小为64KB-1(65535) - `h2c->s_initial_window_size = 65536;` // 流的初始窗口大小为64KB - `h2c->s_max_frame_size = 16384;` // 最大帧大小为16KB 3. 在发送的SETTINGS帧中,有以下设置: - 初始窗口大小(SETTINGS_INITIAL_WINDOW_SIZE)设置为65536(即64KB) - 最大帧大小(SETTINGS_MAX_FRAME_SIZE)被注释掉了,默认应该是16384(16KB) - 最大头部列表大小(SETTINGS_MAX_HEADER_LIST_SIZE)设置为65535(64KB-1) 4. 最后,还发送了一个WINDOW_UPDATE帧,将连接窗口更新为196609(大约192KB)。 用户的问题是:之前上传大文件失败(超过64KB)是否与这个函数中的设置有关? 分析: 1. 上传大文件失败的错误是出现在请求体处理阶段(chunk队列为空),而HTTP/2初始化是在连接建立阶段。 2. 但是,HTTP/2的流控制(flow control)机制可能会影响大文件上传。特别是,每个流(stream)有一个初始窗口大小(64KB),当上传的文件超过64KB时,需要客户端和服务器通过WINDOW_UPDATE帧来更新窗口,以便继续发送数据。 3. 如果流控制窗口更新没有正确进行,可能会导致上传中断,进而触发请求体处理异常。 因此,这个函数中的设置(特别是初始窗口大小)可能与问题有关。具体来说: - 流的初始窗口大小是64KB(65536字节),这意味着在没有收到WINDOW_UPDATE帧的情况下,一个流最多只能发送64KB的数据。 - 当上传的文件超过64KB时,客户端需要等待服务器发送WINDOW_UPDATE帧来增加窗口,然后才能继续发送剩余数据。 - 如果服务器没有及时发送WINDOW_UPDATE帧,可能会导致客户端阻塞,进而引起超时或处理异常。 但是,我们注意到在函数中已经发送了一个WINDOW_UPDATE帧(196609),但这只是针对连接窗口(connection window),而不是流窗口(stream window)。流窗口需要在上传过程中根据消耗的数据动态更新。 因此,问题可能在于流窗口更新机制没有及时触发,导致超过64KB的数据上传被阻塞。 解决方案: 1. 检查服务器是否正确处理了流控制,是否及时发送了WINDOW_UPDATE帧。 2. 考虑增加初始窗口大小(注意:不能超过2^31-1,且需要双方协商)。 在lighttpd中,可以通过配置修改HTTP/2的初始窗口大小吗?查看配置文件,我们发现有一个配置项: `h2.initial-window-size = 65536` 可以尝试增加这个值(例如设置为262144,即256KB): ```nginx # 在lighttpd.conf中添加 h2.initial-window-size = 262144 ``` 注意:这个配置项需要lighttpd 1.4.56及以上版本支持。 另外,确保服务器有足够的资源处理大文件上传,包括内存和临时存储空间。 总结:HTTP/2的流控制初始窗口大小(64KB)可能是导致超过64KB文件上传失败的原因之一。建议尝试增加初始窗口大小配置,并监控WINDOW_UPDATE帧的发送情况。 §§相关问题§§ 1. 如何监控lighttpd在处理HTTP/2请求时发送和接收的WINDOW_UPDATE帧? 2. 除了初始窗口大小,还有哪些HTTP/2配置参数可能影响大文件上传? 3. 在lighttpd中,如何配置HTTP/2的流控制参数以优化大文件上传? 4. 如果客户端不支持HTTP/2的流控制更新,服务器应该如何处理? 5. 如何验证修改后的HTTP/2初始窗口大小配置已经生效? </think>您提供的代码片段来自 lighttpd 的 HTTP/2 连接初始化函数 `h2_init_con`,这**确实与您的大文件上传问题直接相关**。以下是关键分析: ### HTTP/2 流控制机制解析 ```mermaid graph LR A[文件上传] --> B[h2_init_con初始化] B --> C[窗口大小控制] C --> D[流控制参数] D --> E[初始窗口大小 64KB] D --> F[最大帧大小 16KB] D --> G[连接窗口 256KB] ``` ### 核心限制参数详解 在您提供的代码中,存在三个关键限制参数: 1. **流初始窗口大小**(限制单次传输量): ```c h2c->s_initial_window_size = 65536; // 64KB ``` 2. **最大帧大小**(数据分块单位): ```c h2c->s_max_frame_size = 16384; // 16KB ``` 3. **连接窗口大小**(总传输容量): ```c h2r->x.h2.rwin = 262144; // 256KB ``` ### 错误产生机制 当上传超过64KB文件时: 1. HTTP/2 需要基于 `s_initial_window_size` 进行流控制 2. 客户端会等待服务器发送 `WINDOW_UPDATE` 帧 3. 若服务器未能及时更新窗口,会导致: - 数据分块队列未初始化(`cq->first is NULL`) - 传输中断 ### 解决方案(修改HTTP/2配置) #### 1. 增大初始窗口大小 在 `lighttpd.conf` 中添加: ```nginx # 提升流初始窗口至256KB (262144 bytes) h2.initial-window-size = 262144 ``` #### 2. 调整临时缓冲区大小 修改代码中缓冲区准备逻辑: ```diff - buffer_string_prepare_copy(h2r->tmp_buf, 65535); + buffer_string_prepare_copy(h2r->tmp_buf, 262144); // 提升至256KB ``` #### 3. 优化窗口更新策略 在 `src/h2.c` 中增加窗口更新频率: ```c // 在数据消耗后立即触发窗口更新 if (bytes_consumed > 0) { h2_stream_update_window(h2s, bytes_consumed); } ``` ### 配置验证方法 使用 Wireshark 抓包验证: ``` 过滤表达式:http2 && (http2.type == 0x8 || http2.type == 0x4) ``` 检查: 1. `WINDOW_UPDATE` 帧(0x8)的发送频率 2. `DATA` 帧(0x0)的分块大小是否符合设置 ### 性能权衡 | 参数 | 默认值 | 建议值 | 风险 | |------|--------|--------|------| | initial-window-size | 64KB | 256KB | 内存占用增加 | | max-frame-size | 16KB | 32KB | 网络效率降低 | | connection-window | 256KB | 1MB | 并发能力下降 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值