当前位置: 首页 > news >正文

wordpress 移动 建站福州短视频seo网红

wordpress 移动 建站,福州短视频seo网红,深圳网站建设 猴王网络,广告设计公司的成本票项目有哪些前言 项目源码地址 项目详细介绍 项目简介#xff1a; Linux下C轻量级Web服务器#xff0c;助力初学者快速实践网络编程#xff0c;搭建属于自己的服务器. 使用 线程池 非阻塞socket epoll(ET和LT均实现) 事件处理(Reactor和模拟Proactor均实现) 的并发模型使用状态机…前言 项目源码地址 项目详细介绍 项目简介 Linux下C轻量级Web服务器助力初学者快速实践网络编程搭建属于自己的服务器. 使用 线程池 非阻塞socket epoll(ET和LT均实现) 事件处理(Reactor和模拟Proactor均实现) 的并发模型使用状态机解析HTTP请求报文支持解析GET和POST请求访问服务器数据库实现web端用户注册、登录功能可以请求服务器图片和视频文件实现同步/异步日志系统记录服务器运行状态经Webbench压力测试可以实现上万的并发连接数据交换 http_conn.cpp利用一个主从状态机来处理客户端的htttp连接并生成相应的响应。主要内容如下 根据状态转移,通过主从状态机封装了http连接类。其中,主状态机在内部调用从状态机,从状态机将处理状态和数据传给主状态机 客户端发出http连接请求从状态机读取数据,更新自身状态和接收数据,传给主状态机主状态机根据从状态机状态,更新自身状态,决定响应请求还是继续读取 原项目地址的注释较少不适合初学者于是我将每行都加上了注释帮助大家更好的理解: #include http_conn.h #include mysql/mysql.h #include fstream// 定义HTTP响应的一些状态信息用于不同HTTP请求返回的状态码和描述 const char *ok_200_title OK; const char *error_400_title Bad Request; // 客户端请求有语法错误服务器无法处理 const char *error_400_form Your request has bad syntax or is inherently impossible to satisfy.\n; const char *error_403_title Forbidden; // 客户端没有访问权限 const char *error_403_form You do not have permission to get file from this server.\n; const char *error_404_title Not Found; // 请求的资源不存在 const char *error_404_form The requested file was not found on this server.\n; const char *error_500_title Internal Error; // 服务器内部错误 const char *error_500_form There was an unusual problem serving the request file.\n;// 用于线程安全操作的锁 locker m_lock;// 存储用户名和密码的映射用于验证登录和注册 mapstring, string users;// 初始化数据库结果将数据库中的用户信息读取到内存中 void http_conn::initmysql_result(connection_pool *connPool) {// 从连接池中取出一个MYSQL连接MYSQL *mysql NULL;connectionRAII mysqlcon(mysql, connPool);// 查询user表中的username和passwd字段获取用户信息if (mysql_query(mysql, SELECT username,passwd FROM user)){LOG_ERROR(SELECT error:%s\n, mysql_error(mysql));}// 获取查询结果MYSQL_RES *result mysql_store_result(mysql);// 获取结果集中字段的数量int num_fields mysql_num_fields(result);// 获取所有字段的信息MYSQL_FIELD *fields mysql_fetch_fields(result);// 遍历结果集的每一行将用户名和密码存入map中while (MYSQL_ROW row mysql_fetch_row(result)){string temp1(row[0]); // 用户名string temp2(row[1]); // 密码users[temp1] temp2; // 存入map} }// 设置文件描述符为非阻塞模式 int setnonblocking(int fd) {int old_option fcntl(fd, F_GETFL); // 获取当前的文件描述符状态标志int new_option old_option | O_NONBLOCK; // 添加非阻塞标志fcntl(fd, F_SETFL, new_option); // 设置新的文件描述符状态return old_option; // 返回旧的文件描述符状态 }// 向内核事件表注册读事件并设置触发模式为ET或LT模式同时选择是否启用EPOLLONESHOT模式 void addfd(int epollfd, int fd, bool one_shot, int TRIGMode) {epoll_event event;event.data.fd fd; // 绑定fdif (1 TRIGMode) // ET模式下添加EPOLLET标志event.events EPOLLIN | EPOLLET | EPOLLRDHUP; // EPOLLRDHUP表示对端关闭连接elseevent.events EPOLLIN | EPOLLRDHUP; // LT模式下if (one_shot) // 是否启用EPOLLONESHOT模式防止同一个socket被多个线程处理event.events | EPOLLONESHOT;epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, event); // 向epoll实例中注册事件setnonblocking(fd); // 设置非阻塞 }// 从内核事件表中删除文件描述符 void removefd(int epollfd, int fd) {epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, 0); // 删除指定文件描述符的事件close(fd); // 关闭文件描述符 }// 修改文件描述符上的注册事件重置EPOLLONESHOT void modfd(int epollfd, int fd, int ev, int TRIGMode) {epoll_event event;event.data.fd fd;if (1 TRIGMode) // ET模式event.events ev | EPOLLET | EPOLLONESHOT | EPOLLRDHUP;else // LT模式event.events ev | EPOLLONESHOT | EPOLLRDHUP;epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, event); // 修改事件 }int http_conn::m_user_count 0; // 用户数量初始化为0 int http_conn::m_epollfd -1; // epoll实例文件描述符初始化为-1// 关闭连接减少用户计数 void http_conn::close_conn(bool real_close) {if (real_close (m_sockfd ! -1)) // 只有当real_close为true并且socket存在时才关闭连接{printf(close %d\n, m_sockfd);removefd(m_epollfd, m_sockfd); // 从epoll中移除该文件描述符m_sockfd -1; // 重置socket描述符m_user_count--; // 用户总量减1} }// 初始化连接的相关信息 void http_conn::init(int sockfd, const sockaddr_in addr, char *root, int TRIGMode,int close_log, string user, string passwd, string sqlname) {m_sockfd sockfd; // 保存传入的socket文件描述符m_address addr; // 保存客户端的地址信息addfd(m_epollfd, sockfd, true, m_TRIGMode); // 注册epoll事件并且启用EPOLLONESHOT模式m_user_count; // 新增一个用户// 初始化一些相关参数如网站根目录、触发模式、是否关闭日志等doc_root root;m_TRIGMode TRIGMode;m_close_log close_log;strcpy(sql_user, user.c_str()); // 保存数据库用户名strcpy(sql_passwd, passwd.c_str()); // 保存数据库密码strcpy(sql_name, sqlname.c_str()); // 保存数据库名init(); // 调用init()函数初始化其他成员变量 }// 初始化连接的一些内部状态 void http_conn::init() {mysql NULL;bytes_to_send 0;bytes_have_send 0;m_check_state CHECK_STATE_REQUESTLINE; // 初始状态为解析请求行m_linger false;m_method GET; // 默认请求方法为GETm_url 0;m_version 0;m_content_length 0;m_host 0;m_start_line 0;m_checked_idx 0;m_read_idx 0;m_write_idx 0;cgi 0; // CGI标志初始化为0m_state 0;timer_flag 0;improv 0;// 初始化读写缓冲区memset(m_read_buf, \0, READ_BUFFER_SIZE);memset(m_write_buf, \0, WRITE_BUFFER_SIZE);memset(m_real_file, \0, FILENAME_LEN); }// 从状态机用于逐行解析读取到的数据 http_conn::LINE_STATUS http_conn::parse_line() {char temp;// 遍历缓冲区从m_checked_idx位置开始逐字符检查for (; m_checked_idx m_read_idx; m_checked_idx){temp m_read_buf[m_checked_idx];// 如果当前字符为回车符if (temp \r){// 如果回车符是缓冲区最后一个字符则表示还没有完整的一行返回LINE_OPENif ((m_checked_idx 1) m_read_idx)return LINE_OPEN;// 如果回车符后面是换行符说明读取到了一行完整的请求else if (m_read_buf[m_checked_idx 1] \n){m_read_buf[m_checked_idx] \0; // 将回车符替换为字符串结束符m_read_buf[m_checked_idx] \0; // 将换行符替换为字符串结束符return LINE_OK; // 返回LINE_OK表示读取到了一行}return LINE_BAD; // 如果不是换行符说明请求行格式错误}// 如果当前字符是换行符else if (temp \n){// 检查前一个字符是否为回车符if (m_checked_idx 1 m_read_buf[m_checked_idx - 1] \r){m_read_buf[m_checked_idx - 1] \0; // 将回车符替换为字符串结束符m_read_buf[m_checked_idx] \0; // 将换行符替换为字符串结束符return LINE_OK;}return LINE_BAD; // 如果前一个字符不是回车符则返回LINE_BAD}}return LINE_OPEN; // 如果没有遇到回车换行表示行不完整返回LINE_OPEN }// 循环读取客户端数据直到无数据可读或对方关闭连接 bool http_conn::read_once() {if (m_read_idx READ_BUFFER_SIZE) // 如果读缓冲区已满则返回false{return false;}int bytes_read 0;// LT模式读取数据if (0 m_TRIGMode){// 从socket中读取数据存储到读缓冲区bytes_read recv(m_sockfd, m_read_buf m_read_idx, READ_BUFFER_SIZE - m_read_idx, 0);m_read_idx bytes_read;if (bytes_read 0) // 如果读取到的数据为空或发生错误{return false;}return true;}// ET模式读取数据需要循环读取直到没有数据可读else{while (true){// 尝试读取数据bytes_read recv(m_sockfd, m_read_buf m_read_idx, READ_BUFFER_SIZE - m_read_idx, 0);if (bytes_read -1) // 出现错误{// 如果错误是EAGAIN或者EWOULDBLOCK表示数据已经全部读取完毕if (errno EAGAIN || errno EWOULDBLOCK)break;return false; // 否则发生了其他错误}else if (bytes_read 0) // 对方关闭了连接{return false;}m_read_idx bytes_read; // 更新读索引}return true;} }// 解析HTTP请求行获取请求方法、目标URL及HTTP版本号 http_conn::HTTP_CODE http_conn::parse_request_line(char *text) {m_url strpbrk(text, \t); // 查找请求行中的第一个空格或制表符后面是URLif (!m_url){return BAD_REQUEST; // 如果没有找到空格或制表符说明请求行格式错误}*m_url \0; // 将空格或制表符替换为字符串结束符分离出请求方法char *method text; // 获取请求方法if (strcasecmp(method, GET) 0) // 比较请求方法是否为GETm_method GET;else if (strcasecmp(method, POST) 0) // 比较请求方法是否为POST{m_method POST;cgi 1; // 如果是POST方法开启CGI处理}elsereturn BAD_REQUEST; // 如果不是GET或POST返回BAD_REQUESTm_url strspn(m_url, \t); // 跳过URL前的空格或制表符m_version strpbrk(m_url, \t); // 查找URL后的空格或制表符后面是HTTP版本if (!m_version)return BAD_REQUEST; // 如果没有找到返回BAD_REQUEST*m_version \0; // 将空格或制表符替换为字符串结束符分离出URLm_version strspn(m_version, \t); // 跳过版本号前的空格或制表符if (strcasecmp(m_version, HTTP/1.1) ! 0) // 检查是否为HTTP/1.1return BAD_REQUEST;// 如果URL是以http://或https://开头跳过协议部分if (strncasecmp(m_url, http://, 7) 0){m_url 7;m_url strchr(m_url, /); // 查找URL路径部分}if (strncasecmp(m_url, https://, 8) 0){m_url 8;m_url strchr(m_url, /);}if (!m_url || m_url[0] ! /) // 如果URL无效或不以/开头返回BAD_REQUESTreturn BAD_REQUEST;if (strlen(m_url) 1) // 如果URL为/显示默认页面strcat(m_url, judge.html);m_check_state CHECK_STATE_HEADER; // 切换状态到解析请求头return NO_REQUEST; }// 解析HTTP请求的头部信息 http_conn::HTTP_CODE http_conn::parse_headers(char *text) {if (text[0] \0) // 如果当前头部信息为空表示解析完毕{if (m_content_length ! 0) // 如果有消息体切换到解析消息体的状态{m_check_state CHECK_STATE_CONTENT;return NO_REQUEST;}return GET_REQUEST; // 如果没有消息体说明请求已完整返回GET_REQUEST}// 解析Connection头部判断是否为长连接else if (strncasecmp(text, Connection:, 11) 0){text 11;text strspn(text, \t);if (strcasecmp(text, keep-alive) 0){m_linger true; // 如果是keep-alive保持长连接}}// 解析Content-Length头部获取消息体的长度else if (strncasecmp(text, Content-length:, 15) 0){text 15;text strspn(text, \t);m_content_length atol(text); // 将字符串转换为长整型表示消息体长度}// 解析Host头部获取主机名else if (strncasecmp(text, Host:, 5) 0){text 5;text strspn(text, \t);m_host text; // 保存主机名}else{LOG_INFO(oop!unknow header: %s, text); // 记录未知的头部字段}return NO_REQUEST; // 继续解析其他头部 }// 解析HTTP请求的消息体 http_conn::HTTP_CODE http_conn::parse_content(char *text) {if (m_read_idx (m_content_length m_checked_idx)) // 检查是否完整读取了消息体{text[m_content_length] \0; // 将消息体以\0结束m_string text; // 将消息体存储起来通常是POST请求的参数return GET_REQUEST; // 消息体解析完成返回GET_REQUEST}return NO_REQUEST; // 消息体还未解析完整继续读取 }// 主状态机处理入口依次调用解析请求行、请求头、消息体的函数 http_conn::HTTP_CODE http_conn::process_read() {LINE_STATUS line_status LINE_OK; // 当前行的解析状态HTTP_CODE ret NO_REQUEST; // HTTP请求的解析结果char *text 0;// 循环解析HTTP请求直到完整解析或遇到错误while ((m_check_state CHECK_STATE_CONTENT line_status LINE_OK) || ((line_status parse_line()) LINE_OK)){text get_line(); // 获取解析到的一行数据m_start_line m_checked_idx; // 更新已解析的起始位置LOG_INFO(%s, text); // 记录解析到的内容switch (m_check_state) // 根据当前解析状态处理不同部分{case CHECK_STATE_REQUESTLINE: // 解析请求行{ret parse_request_line(text); // 调用parse_request_line()函数解析if (ret BAD_REQUEST) // 如果解析失败返回错误return BAD_REQUEST;break;}case CHECK_STATE_HEADER: // 解析请求头{ret parse_headers(text); // 调用parse_headers()函数解析if (ret BAD_REQUEST) // 如果解析失败返回错误return BAD_REQUEST;else if (ret GET_REQUEST) // 如果请求完整执行do_request(){return do_request();}break;}case CHECK_STATE_CONTENT: // 解析消息体{ret parse_content(text); // 调用parse_content()函数解析if (ret GET_REQUEST) // 如果解析成功执行do_request()return do_request();line_status LINE_OPEN; // 如果消息体不完整继续等待数据break;}default:return INTERNAL_ERROR; // 发生未知错误返回服务器内部错误}}return NO_REQUEST; // 如果还未解析完成返回NO_REQUEST }// 处理HTTP请求生成相应的响应 http_conn::HTTP_CODE http_conn::do_request() {strcpy(m_real_file, doc_root); // 将网站根目录复制到m_real_file中int len strlen(doc_root); // 获取根目录路径的长度const char *p strrchr(m_url, /); // 查找请求的最后一个/区分不同的URL// 如果是POST请求且URL是登录或注册请求if (cgi 1 (*(p 1) 2 || *(p 1) 3)){// 根据请求的类型判断是登录还是注册char flag m_url[1];char *m_url_real (char *)malloc(sizeof(char) * 200); // 动态分配内存strcpy(m_url_real, /);strcat(m_url_real, m_url 2); // 构造实际文件路径strncpy(m_real_file len, m_url_real, FILENAME_LEN - len - 1); // 拼接完整路径free(m_url_real); // 释放动态内存// 解析POST请求的用户名和密码char name[100], password[100];int i;for (i 5; m_string[i] ! ; i)name[i - 5] m_string[i]; // 提取用户名name[i - 5] \0;int j 0;for (i i 10; m_string[i] ! \0; i, j)password[j] m_string[i]; // 提取密码password[j] \0;// 如果是注册请求if (*(p 1) 3){// 检查数据库中是否存在同名用户char *sql_insert (char *)malloc(sizeof(char) * 200);strcpy(sql_insert, INSERT INTO user(username, passwd) VALUES();strcat(sql_insert, );strcat(sql_insert, name);strcat(sql_insert, , );strcat(sql_insert, password);strcat(sql_insert, ));if (users.find(name) users.end()) // 如果用户不存在插入新用户{m_lock.lock(); // 加锁防止并发修改int res mysql_query(mysql, sql_insert); // 执行插入语句users.insert(pairstring, string(name, password)); // 更新内存中的用户表m_lock.unlock(); // 解锁if (!res)strcpy(m_url, /log.html); // 注册成功跳转到登录页面elsestrcpy(m_url, /registerError.html); // 注册失败跳转到错误页面}elsestrcpy(m_url, /registerError.html); // 用户已存在返回错误页面}// 如果是登录请求else if (*(p 1) 2){// 检查用户名和密码是否匹配if (users.find(name) ! users.end() users[name] password)strcpy(m_url, /welcome.html); // 登录成功跳转到欢迎页面elsestrcpy(m_url, /logError.html); // 登录失败跳转到错误页面}}// 根据URL后缀处理不同的页面请求if (*(p 1) 0){char *m_url_real (char *)malloc(sizeof(char) * 200);strcpy(m_url_real, /register.html); // 注册页面strncpy(m_real_file len, m_url_real, strlen(m_url_real));free(m_url_real);}else if (*(p 1) 1){char *m_url_real (char *)malloc(sizeof(char) * 200);strcpy(m_url_real, /log.html); // 登录页面strncpy(m_real_file len, m_url_real, strlen(m_url_real));free(m_url_real);}else if (*(p 1) 5){char *m_url_real (char *)malloc(sizeof(char) * 200);strcpy(m_url_real, /picture.html); // 图片页面strncpy(m_real_file len, m_url_real, strlen(m_url_real));free(m_url_real);}else if (*(p 1) 6){char *m_url_real (char *)malloc(sizeof(char) * 200);strcpy(m_url_real, /video.html); // 视频页面strncpy(m_real_file len, m_url_real, strlen(m_url_real));free(m_url_real);}else if (*(p 1) 7){char *m_url_real (char *)malloc(sizeof(char) * 200);strcpy(m_url_real, /fans.html); // 粉丝页面strncpy(m_real_file len, m_url_real, strlen(m_url_real));free(m_url_real);}elsestrncpy(m_real_file len, m_url, FILENAME_LEN - len - 1); // 其他请求拼接实际文件路径// 检查文件是否存在if (stat(m_real_file, m_file_stat) 0)return NO_RESOURCE; // 文件不存在返回NO_RESOURCE// 检查文件是否有读取权限if (!(m_file_stat.st_mode S_IROTH))return FORBIDDEN_REQUEST; // 没有权限返回FORBIDDEN_REQUEST// 检查是否是目录if (S_ISDIR(m_file_stat.st_mode))return BAD_REQUEST; // 请求的是目录返回BAD_REQUEST// 打开文件int fd open(m_real_file, O_RDONLY);m_file_address (char *)mmap(0, m_file_stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0); // 将文件映射到内存close(fd); // 关闭文件描述符return FILE_REQUEST; // 返回文件请求 }// 解除内存映射 void http_conn::unmap() {if (m_file_address){munmap(m_file_address, m_file_stat.st_size); // 解除文件的内存映射m_file_address 0; // 重置文件地址指针} }// 向客户端写入HTTP响应 bool http_conn::write() {int temp 0;if (bytes_to_send 0) // 如果要发送的字节为0表示响应已经发送完毕{modfd(m_epollfd, m_sockfd, EPOLLIN); // 修改epoll事件为读事件准备处理下一次请求init(); // 重新初始化连接return true;}// 循环发送响应数据直到全部发送完成或遇到错误while (1){temp writev(m_sockfd, m_iv, m_iv_count); // 使用writev函数将响应数据发送给客户端if (temp 0) // 发送过程中遇到错误{// 如果错误是由于非阻塞写导致的缓冲区已满if (errno EAGAIN){modfd(m_epollfd, m_sockfd, EPOLLOUT); // 重新注册写事件return true;}unmap(); // 如果遇到其他错误取消文件映射return false;}bytes_have_send temp; // 更新已经发送的字节数bytes_to_send - temp; // 更新剩余需要发送的字节数// 如果已经发送完响应头部if (bytes_have_send m_iv[0].iov_len){m_iv[0].iov_len 0; // 清空头部的iov结构体长度m_iv[1].iov_base m_file_address (bytes_have_send - m_write_idx); // 设置发送文件的起始地址m_iv[1].iov_len bytes_to_send; // 更新剩余需要发送的文件长度}else{m_iv[0].iov_base m_write_buf bytes_have_send; // 更新响应头部的发送位置m_iv[0].iov_len - temp; // 更新头部剩余需要发送的长度}if (bytes_to_send 0) // 如果所有数据都已发送完成{unmap(); // 取消文件映射modfd(m_epollfd, m_sockfd, EPOLLIN); // 重新注册读事件if (m_linger) // 如果是长连接{init(); // 重新初始化连接等待处理新的请求return true;}else{return false; // 如果不是长连接关闭连接}}} }// 将HTTP响应生成并写入缓冲区 bool http_conn::add_response(const char *format, ...) {if (m_write_idx WRITE_BUFFER_SIZE) // 如果写入的响应数据超出缓冲区大小返回false{return false;}va_list arg_list;va_start(arg_list, format); // 开始可变参数处理int len vsnprintf(m_write_buf m_write_idx, WRITE_BUFFER_SIZE - 1 - m_write_idx, format, arg_list); // 格式化输出到缓冲区if (len (WRITE_BUFFER_SIZE - 1 - m_write_idx)) // 如果格式化后的数据超出缓冲区大小返回false{va_end(arg_list);return false;}m_write_idx len; // 更新缓冲区索引va_end(arg_list);LOG_INFO(request:%s, m_write_buf); // 记录生成的响应return true; }// 向响应中添加状态行 bool http_conn::add_status_line(int status, const char *title) {return add_response(%s %d %s\r\n, HTTP/1.1, status, title); // 将状态行写入响应中 }// 向响应中添加头部信息 bool http_conn::add_headers(int content_len) {add_content_length(content_len); // 添加Content-Length头部指定响应内容长度add_linger(); // 添加Connection头部指定是否保持连接add_blank_line(); // 添加空行表示头部结束return true; }// 向响应中添加Content-Length头部 bool http_conn::add_content_length(int content_len) {return add_response(Content-Length:%d\r\n, content_len); // 写入Content-Length头部 }// 向响应中添加Connection头部 bool http_conn::add_linger() {return add_response(Connection:%s\r\n, (m_linger true) ? keep-alive : close); // 根据长连接状态写入Connection头部 }// 向响应中添加空行 bool http_conn::add_blank_line() {return add_response(%s, \r\n); // 写入空行 }// 向响应中添加实际内容 bool http_conn::add_content(const char *content) {return add_response(%s, content); // 将内容写入响应 }// 处理向客户端返回的完整响应 bool http_conn::process_write(HTTP_CODE ret) {switch (ret){case INTERNAL_ERROR: // 内部错误时的响应{add_status_line(500, error_500_title); // 添加状态行状态码500add_headers(strlen(error_500_form)); // 添加响应头if (!add_content(error_500_form)) // 添加错误内容return false;break;}case BAD_REQUEST: // 错误请求时的响应{add_status_line(400, error_400_title); // 添加状态行状态码400add_headers(strlen(error_400_form)); // 添加响应头if (!add_content(error_400_form)) // 添加错误内容return false;break;}case NO_RESOURCE: // 资源不存在时的响应{add_status_line(404, error_404_title); // 添加状态行状态码404add_headers(strlen(error_404_form)); // 添加响应头if (!add_content(error_404_form)) // 添加错误内容return false;break;}case FORBIDDEN_REQUEST: // 没有权限访问时的响应{add_status_line(403, error_403_title); // 添加状态行状态码403add_headers(strlen(error_403_form)); // 添加响应头if (!add_content(error_403_form)) // 添加错误内容return false;break;}case FILE_REQUEST: // 正常的文件请求{add_status_line(200, ok_200_title); // 添加状态行状态码200if (m_file_stat.st_size ! 0) // 如果请求的文件不为空{add_headers(m_file_stat.st_size); // 添加响应头指定内容长度为文件大小m_iv[0].iov_base m_write_buf; // 设置第一块内存区域为响应头部m_iv[0].iov_len m_write_idx;m_iv[1].iov_base m_file_address; // 设置第二块内存区域为文件内容m_iv[1].iov_len m_file_stat.st_size;m_iv_count 2;bytes_to_send m_write_idx m_file_stat.st_size; // 更新需要发送的总字节数return true;}else{const char *ok_string htmlbody/body/html; // 如果文件为空返回一个简单的HTML页面add_headers(strlen(ok_string)); // 添加响应头if (!add_content(ok_string)) // 添加空页面的内容return false;}}default:return false;}m_iv[0].iov_base m_write_buf; // 设置第一块内存区域为响应头部m_iv[0].iov_len m_write_idx;m_iv_count 1;bytes_to_send m_write_idx; // 更新需要发送的字节数return true; }// 主逻辑函数负责处理HTTP请求并生成响应 void http_conn::process() {HTTP_CODE read_ret process_read(); // 调用process_read解析HTTP请求if (read_ret NO_REQUEST) // 如果请求不完整继续监听{modfd(m_epollfd, m_sockfd, EPOLLIN);return;}bool write_ret process_write(read_ret); // 生成响应if (!write_ret){close_conn(); // 如果生成响应失败关闭连接}modfd(m_epollfd, m_sockfd, EPOLLOUT); // 修改epoll事件为写事件准备发送响应 }
http://www.sczhlp.com/news/227214/

相关文章:

  • 路桥网站建设前端开发培训找不到工作
  • 给你一个网站你怎么做的吗石家庄最新一例轨迹
  • VMware Workstation Pro和Oracle VM VirtualBox安装kali系统
  • 哪些方法可以建设网站文件上传网站源码
  • 在淘宝做网站可以退货退款么微信用网站怎么做
  • 成都网站设计公司电话简约wordpress模板
  • 吴中区建设局网站建设一个网站预算
  • 深圳市外贸网站怎么去营销自己的产品
  • 乐清定制网站建设北京王府井附近美食攻略
  • 网站开发与管理心得体会网站建设与设计学了做什么的
  • 网站简介模板酷站
  • 个人做网站 用什么语言阿里巴巴国际站费用
  • 哈尔滨建设网站成本会员管理系统功能介绍
  • 怎么在ps里做网站设计做网站程序员
  • 黄埔网站建设(信科网络)衣服网站建设方案书
  • 个人网站 创意程序员一个月能挣多少钱
  • 做自动发卡密网站的教程建筑方案设计师的工作内容
  • 视频网站如何做盗链骏域网站建设专家电脑版
  • 化妆品做备案的网站全球做网站的公司排名
  • 浙江建设厅网站官网北京专业建设网站价格
  • 河南网站建设推广运营网站开发建设技术规范书
  • 网站建设的任务怎么做网页推广
  • 企业建设网站企业做软件的叫什么职业
  • 厦门 做网站编辑网站内容有没有批量办法
  • 网站打不开是怎么回事衡水企业网站建设公司
  • 松江建设新城有限公司网站网站建设公司价格差别
  • 网站建设市场调研框架wordpress 插件 mysql
  • 光速网站建设简述网站设计步骤
  • 【URP】Unity[视差贴图]模拟[风格化地形]实践
  • Windows系统安装了CUDA,但是Python的PyTorch还是没用gpu进行训练