【问题标题】:Unix networking in C++ doesn't wait for a connectionC++ 中的 Unix 网络不等待连接
【发布时间】:2021-07-17 20:58:06
【问题描述】:

我最近一直在学习 Unix 中的网络,并编写了这两个简单的程序,等待连接,接收消息,然后将相同的消息发送回发送者:

发送.cpp

#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <iostream>
#include <unistd.h>

int main(int argc, char const *argv[])
{
    struct addrinfo hints, *res;
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;
    getaddrinfo(NULL,  "2000", &hints, &res);

    int sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    if (auto error = connect(sockfd, res->ai_addr, res->ai_addrlen) < 0){
        std::cout << strerror(errno) << '\n';
        exit(1);
    }

    char msg[] = "Hello, World";
    send(sockfd, &msg, sizeof(msg), 0);
    char input[sizeof(msg)];
    recv(sockfd, &input, sizeof(input), 0);
    std::cout << input << '\n';
    close(sockfd);

    return 0;
}  

receive.cpp

#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/poll.h>
#include <iostream>
#include <unistd.h>

int main(int argc, char const *argv[])
{
    struct addrinfo hints, *res;
    int sockfd, new_fd;

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;

    getaddrinfo(NULL, "2000", &hints, &res);
    sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    bind(sockfd, res->ai_addr, res->ai_addrlen);
    listen(sockfd, 5);

    struct sockaddr_storage their_addr1;
    socklen_t addr_size;
    addr_size = sizeof(their_addr1);
    new_fd = accept(sockfd, (struct sockaddr *)&their_addr1, &addr_size);
    if (new_fd < 0)
    {
        std::cout << "Error" << '\n';
        std::cout << strerror(errno) << '\n';
        exit(1);
    }
    std::cout << "Accepted" << '\n';

    char msg[255];
    auto n = recv(new_fd, &msg, 255, 0);
    std::cout << msg << '\n';
    send(new_fd, &msg, n, 0);

    close(sockfd);
    close(new_fd);

    return 0;
}

如果我运行receive.cpp,然后快速(在大约 5 秒内)运行send.cpp,(从命令行运行两者)程序运行良好,但如果我花费更长的时间,那么发送程序总是得到一个拒绝连接错误,接收程序永远不会终止。据我了解,accept() 调用会阻塞应用程序的其余部分并继续侦听,直到出现有效连接。这不是它的工作原理吗?任何帮助都会非常感谢您。

【问题讨论】:

  • 您不应在send.cpp 中指定AI_PASSIVE,请参阅:man7.org/linux/man-pages/man3/getaddrinfo.3.html。也许就是这样。
  • 即使我用机器本地 IP 地址替换它时,也会发生同样的行为,我使用 AI_PASSIVE 只是为了让它在我的两台机器上都可以工作,而无需修改代码
  • 问题不是你想的那样。首先,检查bind的返回值(与其他所有函数一样)。二、查SO_REUSEADDRTIME_WAIT
  • if (auto error = connect(...) &lt; 0) 不会将error 设置为您的想法,因为&lt; 的优先级高于=。请改用int error; if ((error = connect(...)) &lt; 0)。此外,您没有检查 getaddrinfo()bind()listen() 的返回值。 send.cppgetaddrinfo() 使用的参数对于connect() 是错误的。

标签: c++ networking unix-socket


【解决方案1】:

归功于@n。 1.8e9-where's-my-share m.

问题是由于 TCP/IP 协议等待特定时间以确保所有数据包都已到达,然后才允许相同的 IP 和端口组合,导致“地址已在使用”导致绑定失败再次使用。

修复:

  1. 等待内核放弃端口。

  2. 设置套接字选项以允许使用相同的端口重用 setsockopt()

    int 是=1; if (setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof yes) == -1) { perror("setsockopt"); 退出(1); }

【讨论】:

    猜你喜欢
    • 2013-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-12
    • 1970-01-01
    • 1970-01-01
    • 2021-11-09
    • 1970-01-01
    相关资源
    最近更新 更多