#pragma once #include "acl_cpp/stream/aio_handle.hpp" #include "acl_cpp/ipc/ipc_service.hpp" #include "acl_cpp/http/http_header.hpp" namespace acl { class string; /** * HTTP 服务请求类,子类必须继承该类 */ class ACL_CPP_API http_service_request : public http_header { public: /** * 构造函数 * @param domain {const char*} HTTP 服务器的域名(也可以是IP),非空 * 如果传入了空值,则会 fatal * @param port {unsigned short} HTTP 服务端口 */ http_service_request(const char* domain, unsigned short port); /** * 获得由构造函数输入的 domain * @return {const char*} 永不为空 */ const char* get_domain(void) const; /** * 获得由构造函数输入的 port * @return {unsigned short} */ unsigned short get_port(void) const; /** * 当任务处理完毕或出错时,内部处理过程会自动调用 destroy 接口, * 子类可以在该接口内进行一些释放过程,尤其当该对象是动态创建时, * 子类应该在该函数内 delete this 以删除自己,因为该函数最终肯定 * 会被调用,所以子类不应在其它地方进行析构操作 */ virtual void destroy(void) {} ////////////////////////////////////////////////////////////////////////// // 子类必须实现如此虚接口 /** * 获得 HTTP 请求体数据,该函数会在请求过程中被循环调用,直到返回的数据对象 * 中的数据为空 * @return {const string*} 请求体结果数据,如果返回空指针或返回的缓冲区对象 * 的数据为空(即 string->empty()) 则表示 HTTP 请求体数据结束 * 注意:与其它函数不同,该虚接口是另外的子线程中被调用的,所以如果子类实 * 现了该接口,如果需要调用与原有线程具备竞争的资源时应该注意加锁保护 */ virtual const string* get_body(void); /** * 当获得 HTTP 服务器的 HTTP 响应头时的回调接口 * @param addr {const char*} 与服务器之间的连接地址,格式:IP:PORT * @param hdr {const HTTP_HDR_RES*} HTTP 响应头,该结构定义参见: * acl_project/lib_protocol/include/http/lib_http_struct.h */ virtual void on_hdr(const char* addr, const HTTP_HDR_RES* hdr) = 0; /** * 当获得 HTTP 服务器的 HTTP 响应体时的回调接口,当 HTTP 响应体数据 * 比较大时,该回调会被多次调用,直到出错(会调用 on_error)或数据读完 * 时,该回调的两个参数均 0,当 data 及 dlen 均为 0 时,表明读 HTTP * 响应体结束 * @param data {const char*} 某次读操作时 HTTP 响应体数据 * @param dlen {size_t} 某次读操作时 HTTP 响应体数据长度 * 注:如果 HTTP 响应只有头数据而没有数据体,则也会调用该函数通知用户 * HTTP 会话结束 */ virtual void on_body(const char* data, size_t dlen) = 0; /** * 在 HTTP 请求或响应过程中如果出错,则会调用此接口,通知子类出错, * 在调用此接口后 * @param errnum {http_status_t} 出错码 */ virtual void on_error(http_status_t errnum) = 0; protected: virtual ~http_service_request(void); private: char* domain_; unsigned short port_; }; class aio_socket_stream; class ACL_CPP_API http_service : public ipc_service { public: /** * 构造函数 * @param nthread {int} 如果该值 > 1 则内部自动采用线程池,否则 * 则是一个请求一个线程 * @param nwait {int} 当异步引擎采用 ENGINE_WINMSG 时,为了避免 * 因任务线程发送的数据消息过快而阻塞了主线程的 WIN32 消息循环, * 在任务线程发送数据消息时自动休眠的毫秒数;对于其它异步引擎, * 该值也可以用于限速功能 * @param win32_gui {bool} 是否是窗口类的消息,如果是,则内部的 * 通讯模式自动设置为基于 WIN32 的消息,否则依然采用通用的套接 * 口通讯方式 */ http_service(int nthread = 1, int nwait = 1, bool win32_gui = false); ~http_service(void); /** * 应用调用此函数开始 HTTP 会话过程,由 http_service 类对象负责 * 向服务器异步发出 HTTP 请求,同时异步读取来自于 HTTP 服务器的响应 * @param req {http_service_request*} HTTP 请求类对象 */ void do_request(http_service_request* req); protected: #ifdef WIN32 /** * 基类虚函数,当收到来自于子线程的 win32 消息时的回调函数 * @param hWnd {HWND} 窗口句柄 * @param msg {UINT} 用户自定义消息号 * @param wParam {WPARAM} 参数 * @param lParam {LPARAM} 参数 */ virtual void win32_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); #endif /** * 基类虚函数,当有新连接到达时基类回调此函数 * @param client {aio_socket_stream*} 接收到的新的客户端连接 */ virtual void on_accept(aio_socket_stream* client); /** * 基类虚函数,当监听流成功打开后的回调函数 * @param addr {const char*} 实际的监听地址,格式:IP:PORT */ virtual void on_open(const char*addr); /** * 基类虚函数,当监听流关闭时的回调函数 */ virtual void on_close(void); private: char* addr_; int nwait_; aio_handle_type handle_type_; }; } // namespace acl