【发布时间】:2015-09-14 08:46:08
【问题描述】:
我当前的应用程序是一个用 C 编写的玩具 Web 服务,旨在复制 http://sprunge.us/ 的行为(通过 http POST 获取数据,将其存储到磁盘,向客户端返回数据的 url - 还提供具有之前应要求存储)。
应用程序的结构使得线程池由工作线程(只是一个带有 void* 参数的函数指针)实例化,并打开一个套接字来监听传入的连接。该程序的主循环包括一个sock = accept(...) 调用,然后是一个pool_add_task(worker_function_parse_http, sock),以使请求能够被快速处理。
parse_http worker 解析传入的请求,然后将另一个任务添加到工作队列以存储数据 (POST) 或提供先前存储的数据 (GET)。
我对这种方法的问题源于使用http-parser 库,该库使用回调设计返回解析数据(我查看的所有http 解析器都使用这种风格)。我遇到的问题是这样的:
我的parse_http 工人:
- 缓冲来自接受的套接字的数据(函数的唯一参数,在这个阶段)
根据其 API 设置一个
http-parser对象,并设置回调函数,以便它在完成解析 URL 或 BODY 或其他任何内容时调用。 (这些函数是由http-parserlib 定义的固定类型签名,带有指向包含与调用相关的已解析数据的缓冲区的指针,因此我无法传入自己的变量并以这种方式解决问题。这些函数还向 http 解析器返回状态代码,因此我也不能使用返回值。建议从解析器中获取数据以供以后使用的方法是在回调期间将其复制到全局变量中 - 有趣多个线程。)对缓冲的套接字数据执行解析器。在这个阶段,解析器在解析缓冲区的不同部分时应该调用它的设置回调。回调提供了与每个回调相关的解析数据(例如,提供给 body_parsed 回调函数的 BODY 段)。
嗯,这就是问题所在。解析器已执行,但我无权访问已解析的数据。在这里,我将向队列中添加一个新任务,其中包含一个工作函数来存储接收到的正文数据或另一个来处理对先前存储的数据的 GET 请求。这些函数需要同时提供解析的信息(POST 数据或 GET url)以及接受的套接字,以便现在委派的工作可以响应请求并关闭连接。
当然,这个问题的明显解决方案就是不使用这种带有异步实践的线程池模型,但我现在和以后想知道如何最好地解决这个问题。
如何将这些回调中的解析数据返回到工作线程函数。我考虑过让我的on_url_parsed 和on_body_parsed 完成应用程序的其余工作(存储和检索数据),但当然我不再需要在这些上下文中响应客户端的套接字。
如果需要,我可以在有机会时将源代码发布到项目中。
编辑:事实证明,可以从这个特定的 http-parser 库的回调中访问用户定义的void *,因为回调传递了对具有用户的调用者(解析器对象)的引用- 可定义的数据字段。
【问题讨论】:
标签: c multithreading sockets callback pthreads