C++ 中的 Unix 网络不等待连接

时间:2021-07-17 20:58:06

标签: c++ networking unix-socket

我最近一直在学习 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;
}  

接收.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() 调用会阻止应用程序的其余部分并继续侦听,直到出现有效连接。这不是它的工作原理吗?任何帮助都会非常感谢。

1 个答案:

答案 0 :(得分:1)

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

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

修复:

  1. 等待内核放弃端口。

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

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