【发布时间】:2020-09-12 22:30:35
【问题描述】:
我正在编写一个涉及 epoll 和多线程的小型 Web 服务器。对于小而短的 http/1.1 请求和响应,它按预期工作。但是在处理大文件下载时,它总是被我设计的计时器打断。我使用固定的超时值使计时器过期,但我还有一个 if 语句来检查响应是否发送成功。
static void
_expire_timers(list_t *timers, long timeout)
{
httpconn_t *conn;
int sockfd;
node_t *timer;
long cur_time;
long stamp;
timer = list_first(timers);
if (timer) {
cur_time = mstime();
do {
stamp = list_node_stamp(timer);
conn = (httpconn_t *)list_node_data(timer);
if ((cur_time - stamp >= timeout) && httpconn_close(conn)) {
sockfd = httpconn_sockfd(conn);
DEBSI("[CONN] socket closed, server disconnected", sockfd);
close(sockfd);
list_del(timers, stamp);
}
timer = list_next(timers);
} while (timer);
}
}
我意识到在非阻塞环境中,write() 函数可能会在请求-响应通信期间被中断。我想知道 write() 可以保存多长时间或 write() 可以发送多少数据,所以我可以在我的代码中调整 timout 设置。
这是涉及write()的代码,
void
http_rep_get(int clifd, void *cache, char *path, void *req)
{
httpmsg_t *rep;
int len_msg;
char *bytes;
rep = _get_rep_msg((list_t *)cache, path, req);
bytes = msg_create_rep(rep, &len_msg);
/* send msg */
DEBSI("[REP] Sending reply msg...", clifd);
write(clifd, bytes, len_msg);
/* send body */
DEBSI("[REP] Sending body...", clifd);
write(clifd, msg_body_start(rep), msg_body_len(rep));
free(bytes);
msg_destroy(rep, 0);
}
以下是我用来处理传入请求的epoll循环,
do {
nevents = epoll_wait(epfd, events, MAXEVENTS, HTTP_KEEPALIVE_TIME);
if (nevents == -1) perror("epoll_wait()");
/* expire the timers */
_expire_timers(timers, HTTP_KEEPALIVE_TIME);
/* loop through events */
for (i = 0; i < nevents; i++) {
conn = (httpconn_t *)events[i].data.ptr;
sockfd = httpconn_sockfd(conn);
/* error case */
if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) ||
(!(events[i].events & EPOLLIN))) {
perror("EPOLL ERR|HUP");
list_update(timers, conn, mstime());
break;
}
else if (sockfd == srvfd) {
_receive_conn(srvfd, epfd, cache, timers);
}
else {
/* client socket; read client data and process it */
thpool_add_task(taskpool, httpconn_task, conn);
}
}
} while (svc_running);
http_rep_get() 由线程池处理程序 httpconn_task() 执行,HTTP_KEEPALIVE_TIME 是固定超时。一旦请求到达,处理程序 httpconn_task() 将向计时器添加一个计时器。由于 write() 是在 http_rep_get() 中执行的,我认为它可能会被计时器中断。我想我可以改变写给客户端的方式,但我需要确定 write() 能做多少。
如果你有兴趣,你可以浏览我的项目来帮助我。 https://github.com/grassroot72/Maestro
干杯, 爱德华
【问题讨论】:
-
请提供说明问题的minimal verifiable example。实际上,您的代码中没有显示
write调用,并且不清楚显示的函数与您所询问的内容有何关系。 -
这不是一个最小的可验证示例。所以仍然不清楚你在问什么 - 写入与超时有什么关系?您的代码中没有任何内容可以链接两个代码 sn-ps,因此您根本不清楚您在说什么。请查看:How to ask
-
抱歉提出了一个模棱两可的问题,我会尽力说清楚。
-
write总是可以写得比请求的少,所以你需要放在一个循环中。 (read也是如此。) -
..同样适用于读取/接收,假设 TCP。您必须正确且完整地处理从此类系统调用返回的结果。此外,发送“乒乓”回复会使您的协议受到很大的延迟延迟:(
标签: c multithreading webserver keep-alive epoll