gpt4 book ai didi

C++:在 "try"外部创建的类型会导致错误,但在内部不会

转载 作者:搜寻专家 更新时间:2023-10-31 01:24:14 25 4
gpt4 key购买 nike

从纯粹的问题解决的角度来看,这是一个已解决的问题,但包括我在内的某些人可能会对底层机制感兴趣。

我写了一个非常基本的服务器,监听给定的 TCP 端口。我以一种方式编写它,它可以接受多个请求,而不仅仅是一个请求然后退出,带有 while 循环。

由于我没有使用 C++ 的经验,所以我在 google 上搜索了一个解决方案并根据我的需要制作了它。有问题的代码部分如下所示:

    socklen_t addrlen = sizeof(address);

while(true) {
try {
std::cerr << "Listening..." << std::endl;
if(listen(socketId, 3) < 0) {
std::cerr << "Error while listening for incoming connections" << std::endl;
throw;
}
processRequest(accept(socketId, (struct sockaddr *) &address, &addrlen));
} catch(Json::RuntimeError& e) {
std::cerr << "Json error: " << e.what() << std::endl;
} catch(...) {
std::cerr << "Unknown error" << std::endl;
throw;
}
}

这段代码的问题很棘手,对于你们这些更有经验的人来说可能是显而易见的,但对我来说绝对不是显而易见的。

我向您展示类定义的一部分:

    int socketId;
sockaddr_in address;
const RequestProcessor& processor;

注意这些变量的顺序。

使用上面的方法和这个顺序的变量,第一个请求运行顺利,软件开始监听下一个请求。

然而,当第二个请求到达时,processor 引用被覆盖,大概是因为发生了一些内存溢出 - 或者不管它叫什么 - 发生了,这重写了 processor< 的内存位置 引用指向,在此处未显示的方法的某处导致错误。

解决方案很简单,但很难找到:

    while(true) {
try {
std::cerr << "Listening..." << std::endl;
if(listen(socketId, 3) < 0) {
std::cerr << "Error while listening for incoming connections" << std::endl;
throw;
}
socklen_t addrlen = sizeof(address);
processRequest(accept(socketId, (struct sockaddr *) &address, &addrlen));
} catch(Json::RuntimeError& e) {
std::cerr << "Json error: " << e.what() << std::endl;
} catch(...) {
std::cerr << "Unknown error" << std::endl;
throw;
}
}

我所做的只是替换 addrlen 变量的创建位置。这解决了问题并且有一个额外的好处,即更“合理的外观”。

问题是:为什么移动addrlen的初始化可以解决这个问题?

最佳答案

accept 使用它的第三个参数(即 addrlen)作为输入和输出。输入必须是第二个参数指向的结构的大小(即 address),输出将是地址的实际大小。

如果地址不符合结构,根据第三个参数的输入,地址可能会被截断。

如果 acceptaddrlen 返回一个比 sizeof(address) 更大的值,那么在第二次迭代中传递给 的参数accept 将不再匹配 sizeof(address) 并且会导致未定义的行为。实际上,accept 会将超出 address 的地址写入 processor,如果类成员按该顺序布局的话。

在调用 accept 之前的每个循环迭代中将 addrlen 设置为 sizeof(address) 是正确的做法,并确保此值始终用作 accept 的输入,即使 accept 在输出时修改了它的值。

还要确保您使用的sockaddr_* 类型适用于您用于监听套接字的协议(protocol)系列,即sockaddr_in 用于AF_INET (ipv4) 或 sockaddr_in6 用于 AF_INET6 (ipv6)。

关于C++:在 "try"外部创建的类型会导致错误,但在内部不会,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58357907/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com