C++服务器使用poll()没有响应
No response from C++ server using poll()
我正在学习Bgnet指南中的C++和套接字。我做了一个简单的服务器,它只发送一个文本给使用子进程和select((方式连接的人。现在我正在尝试创建一个使用poll()
和std::vector来存储套接字的容器。
问题是它编译正常,但当我运行它并尝试从浏览器连接时,与我所做的其他操作不同,它不会发送响应,浏览器将永远等待。
我检查了很多次代码,没有发现任何错误或逻辑问题。来源在这里:
#include <sys/types.h>
#include <sys/socket.h>
#include <poll.h>
#include <vector>
#include <algorithm>
#include <netdb.h>
#include <cstdio>
#include <string.h>
#include <unistd.h>
#define PORT "19456"
#define BACKLOG 10
using namespace std;
int main() {
sockaddr_storage remote_addr;
socklen_t remote_addr_size;
addrinfo settings, *result_info, *info;
int srv_socket, conn_socket, gai_result, send_status, yes = 1;
vector <pollfd> fds;
vector <pollfd>::iterator fd;
vector <pollfd>::const_iterator last_fd;
pollfd listener_fd, new_fd;
memset(&settings, 0, sizeof settings);
settings.ai_family = AF_INET;
settings.ai_socktype = SOCK_STREAM;
settings.ai_flags = AI_PASSIVE;
if((gai_result = getaddrinfo(NULL, PORT, &settings, &result_info)) != 0) {
fprintf(stderr, "getaddrinfo: %sn", gai_strerror(gai_result));
return 1;
}
for(info = result_info; info != NULL; info = info->ai_next) {
if((srv_socket = socket(info->ai_family, info->ai_socktype, info->ai_protocol)) == -1) {
perror("Error on socket()");
continue;
}
if(setsockopt(srv_socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
close(srv_socket);
perror("Error on setsockopt()");
return 1;
}
if(bind(srv_socket, info->ai_addr, info->ai_addrlen) == -1) {
close(srv_socket);
perror("Error on bind()");
continue;
}
break;
}
if(info == NULL) {
fprintf(stderr, "Failed on all bind()");
return 1;
}
freeaddrinfo(result_info);
if(listen(srv_socket, BACKLOG) == -1) {
perror("Error on listen()");
return 1;
}
listener_fd.fd = srv_socket;
listener_fd.events = POLLIN;
fds.push_back(listener_fd);
while(1) {
pollfd fds_array[fds.size()];
copy(fds.begin(), fds.end(), fds_array);
poll(fds_array, (nfds_t) fds.size(), 0);
if(listener_fd.revents & POLLIN) {
remote_addr_size = sizeof remote_addr;
if((conn_socket = accept(srv_socket, (sockaddr *) &remote_addr, &remote_addr_size)) == -1) {
close(srv_socket);
perror("Error on accept()");
return 1;
}
new_fd.fd = conn_socket;
new_fd.events = POLLOUT;
fds.push_back(new_fd);
}
for(fd = fds.begin() + 1, last_fd = fds.end(); fd != last_fd; ++fd) {
if(fd->revents & POLLOUT) {
send_status = send(fd->fd, "Test", 4, 0);
close(fd->fd);
fds.erase(fd);
if(send_status == -1) {
perror("Error on send()");
return 1;
}
}
}
}
return 0;
}
我搜索了一下,没有发现任何相关的问题,在所有找到的问题中,问题出在语法上。
有人能帮我找出这个错误吗?我将非常感激。
编辑
根据本的回答,我改变了一些事情。现在唯一的问题是连接重置,我认为这是由于在没有读取请求的情况下关闭套接字造成的,另一个问题是服务器使用了超过80%的CPU。使用select((或子进程的方式不会发生这种情况。电流来源:
#include <sys/types.h>
#include <sys/socket.h>
#include <poll.h>
#include <vector>
#include <algorithm>
#include <netdb.h>
#include <cstdio>
#include <string.h>
#include <unistd.h>
#define PORT "19456"
#define BACKLOG 10
using namespace std;
int main() {
sockaddr_storage remote_addr;
socklen_t remote_addr_size;
addrinfo settings, *result_info, *info;
int srv_socket, conn_socket, gai_result, send_status, fd_index, fds_num, yes = 1;
vector <pollfd> fds;
pollfd listener_fd, new_fd;
memset(&settings, 0, sizeof settings);
settings.ai_family = AF_INET;
settings.ai_socktype = SOCK_STREAM;
settings.ai_flags = AI_PASSIVE;
if((gai_result = getaddrinfo(NULL, PORT, &settings, &result_info)) != 0) {
fprintf(stderr, "getaddrinfo: %sn", gai_strerror(gai_result));
return 1;
}
for(info = result_info; info != NULL; info = info->ai_next) {
if((srv_socket = socket(info->ai_family, info->ai_socktype, info->ai_protocol)) == -1) {
perror("Error on socket()");
continue;
}
if(setsockopt(srv_socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
close(srv_socket);
perror("Error on setsockopt()");
return 1;
}
if(bind(srv_socket, info->ai_addr, info->ai_addrlen) == -1) {
close(srv_socket);
perror("Error on bind()");
continue;
}
break;
}
if(info == NULL) {
fprintf(stderr, "Failed on all bind()");
return 1;
}
freeaddrinfo(result_info);
if(listen(srv_socket, BACKLOG) == -1) {
perror("Error on listen()");
return 1;
}
listener_fd.fd = srv_socket;
listener_fd.events = POLLIN;
fds.push_back(listener_fd);
while(1) {
pollfd fds_array[fds.size()];
copy(fds.begin(), fds.end(), fds_array);
poll(fds_array, (nfds_t) fds.size(), 0);
if(fds_array[0].revents & POLLIN) {
remote_addr_size = sizeof remote_addr;
if((conn_socket = accept(srv_socket, (sockaddr *) &remote_addr, &remote_addr_size)) == -1) {
close(srv_socket);
perror("Error on accept()");
return 1;
}
new_fd.fd = conn_socket;
new_fd.events = POLLOUT;
fds.push_back(new_fd);
}
for(fd_index = 1, fds_num = fds.size(); fd_index < fds_num; fd_index++) {
if(fds_array[fd_index].revents & POLLOUT) {
send_status = send(fds_array[fd_index].fd, "Test", 4, 0);
close(fds_array[fd_index].fd);
fds.erase(fds.begin() + fd_index);
if(send_status == -1) {
perror("Error on send()");
return 1;
}
}
}
}
return 0;
}
现在应该是什么问题?
您对accept
是否可用的测试使用了未被poll()
修改的listener_fd
。您必须在fds_array
中使用它的副本,该副本已传递给poll()
。类似地,在发送循环中,您需要对传递给poll()
的数组中的值进行循环。
关于80%的CPU负载,我怀疑您没有正确设置timeout
参数。来自手册:
指定零原因的
timeout
即使没有文件描述符准备好,poll()
也会立即返回。
如果你的服务器工作正常,那么没有理由不输入一个相当大的数字作为超时。我在基于poll/epoll/etc的系统上使用60秒(约60000ms(。
我也看不出你每次都在复制数组的原因。使用std::vector
,您应该能够完全摆脱fds_array
,只需执行以下操作:
poll( &fds[0], (nfds_t) fds.size(), 60000 );
(以及对其余代码的相应更改。(
- 当服务中的事件被触发时,如何将响应从服务发送回客户端?
- C++ 信号和插槽不工作:插槽不响应事件
- NodeJs 服务器充斥着 UDP 广播,不发送响应
- C++关于ENUM的问题。我得到的响应比枚举列表大
- 应用程序在打开的简历中捕获视频后没有响应
- 将继承的结构传递给 poll()
- 使用 cpprest (Casablanca) 返回 PDF 响应
- 为什么当通过 TCP 发送的消息速率增加时,请求-响应消息对的延迟会降低?
- 如何使用从处理程序调度的最终回调将响应异步返回给调用方on_read?
- 获取加密的正文响应WinHttp HTTPS
- QtConcurrent - 在发布到 UI 线程的数千个结果中保持 GUI 响应
- 同步读取多个 TCP 响应
- HTTP 响应格式不正确?
- 如何使用软化工具包从 OPC UA 服务器异步读取操作回调中的数据值响应中获取 NodeId 详细信息
- HTTP帖子,无需等待响应
- 问题导致程序停止响应,并且姓氏未正确打印
- AT 命令响应解析器
- 将静态 IP 分配给我的 ESP32 服务器后不再响应
- 用于C++的 TCP/IP 解析器和响应器
- C++服务器使用poll()没有响应