【问题标题】:Trying to save connections to a member vector - only saving one at a time尝试将连接保存到成员向量 - 一次只保存一个
【发布时间】:2014-03-04 04:54:05
【问题描述】:

我正在尝试编写一个简单的服务器应用程序,它可以从多个客户端获取连接,并将这些连接保存到向量以供另一个对象读取。

我有一个班级NetworkConnection,它是另一个班级Manager的成员。这是我的主要方法:

int main(int argc, const char* argv[])
{
    RoutingManager *manager = new RoutingManager();
    manager->ParseInputFile("topo.txt", 10, 3, " ");

    manager->myConnection = new NetworkConnection("localhost", "7777");
    manager->myConnection->SetSocketHints();
    manager->myConnection->PopulateAddressInfo();
    manager->myConnection->BindSocket();
    manager->myConnection->ListenForConnections();

    return 0;
}

我省略了很多细节,因为它们与您可以在任何地方找到的通用套接字编程指南非常相似......主要问题是在这次通话期间:

int
NetworkConnection::ListenForConnections()
{
    char s[INET6_ADDRSTRLEN];

    if (listen(socketFd, 15) == -1) {
        perror("listen");
        exit(1);
    }
/*
    sigAction.sa_handler = sigchld_handler; // reap all dead processes    
    sigemptyset(&sigAction.sa_mask);
    sigAction.sa_flags = SA_RESTART;
*/
    if (sigaction(SIGCHLD, &sigAction, NULL) == -1) {
        perror("sigaction");
        exit(1);
    }

    printf("server: waiting for connections...\n");

    while(1) {  // main accept() loop
        sin_size = sizeof theirAddress;
        int new_fd = accept(socketFd, (struct sockaddr *)&theirAddress, &sin_size);
        if (new_fd == -1) {
            perror("accept");
            continue;
        }

        inet_ntop(theirAddress.ss_family,
            get_in_addr((struct sockaddr *)&theirAddress),
            s, sizeof s);
        printf("server: got connection from %s\n", s);

        if (!fork()) { // this is the child process
            close(socketFd); // child doesn't need the listener

            NodeConnection nc = NodeConnection();

            char ipstr[INET6_ADDRSTRLEN];
            getpeername(new_fd, (struct sockaddr*)&theirAddress, &sin_size);
            struct sockaddr_in *s = (struct sockaddr_in *)&theirAddress;
            int port = ntohs(s->sin_port);
            inet_ntop(AF_INET, &s->sin_addr, nc.ipstr, sizeof ipstr);

            nc.fd = new_fd;
            nc.theirAddress = theirAddress;
            nc.sin_size = sin_size;
            nc.port = port;

            newConnections.push_back(nc);
            for(vector<NodeConnection>::iterator it = newConnections.begin(); it != newConnections.end(); ++it)
            {                
                cout << "Socket ID: " << it->fd << endl;
                cout << "Their Address: " << it->ipstr << endl;
                cout << "Their Port: " << it->port << endl;
                cout << "My Size: " << newConnections.size() << endl;
                cout << "**************\n";
                //cout << "Their Port: " << (int)ntohs(it->theirAddress.sin_port) << endl;
            }
            exit(0);
        }
       // close(new_fd);  // parent doesn't need this
    }
}

基本上,每当我获得一个新连接时,我都想将该连接的详细信息存储到一个向量中。我决定通过将详细信息添加到 NodeConncetion 结构来做到这一点:

#include <sys/socket.h>
#include <arpa/inet.h>
struct NodeConnection
{
    int fd;
    socklen_t sin_size;
    struct sockaddr_storage theirAddress; 
    char ipstr[INET6_ADDRSTRLEN];
    int port;
};

这样,我的Manager 对象可以轮询这些连接以获取数据。

我遇到的问题是,一旦客户端连接,它就会很好地打印详细信息。当另一个连接时,它也会打印那个的详细信息;但是,它并没有像我预期的那样打印第一个连接,因为我做了一个.push_back(nc) 来保存新的 NodeConnection。

示例输出:

Hints set.
Binding Socket... Socket Bound!
server: waiting for connections...
server: got connection from 127.0.0.1
Socket ID: 4
Their Address: 127.0.0.1
Their Port: 33744
My Size: 1
**************
server: got connection from 127.0.0.1
Socket ID: 5
Their Address: 127.0.0.1
Their Port: 33745
My Size: 1
**************

我可能不完全了解如何保存连接数据..所以如果我以错误的方式解决这个问题,请告诉我。

【问题讨论】:

    标签: c++ multithreading sockets ubuntu multiprocessing


    【解决方案1】:

    在调用 fork() 之后,您正在将连接详细信息推送到子进程中的向量上。

    fork() 创建一个全新的进程,它不与父进程共享任何内存。子级从父级开始,但对子级中的变量所做的更改在父级中不可见,反之亦然。

    所以你的顺序是:

    1. 父级接受连接并创建子级
    2. 子将连接数据添加到其向量(为空)
    3. 子打印向量(现在包含一个条目)
    4. 子退出(它的向量副本现在已经消失)
    5. 从第 1 步开始重复下一个连接。

    如果要保留此连接数据,则需要将其添加到父进程中的向量中。

    我注意到您将您的问题标记为“多线程” - 这可能解释了混乱,因为您的程序不是多线程的,它是多进程的。同一进程中的多个线程确实共享内存。我不建议你改用线程——这会带来一整套你可能不需要的其他问题。

    【讨论】:

    • 很好的解释;谢谢。我不确定如何监听新连接,同时也让它们可用于父线程?这不可能吗?
    • 不是父线程,是父进程!在这种服务器的大多数示例中,父进程不需要连接,它由子进程处理。家长需要这个做什么?
    • 这是一个持久连接 - 所以我们的想法是有一个类来处理所有获取/读取新连接,然后将这些连接提供给启动监听器的类。然后Manager 类可以定期轮询 newConnections 向量以获取详细信息。
    • 您不必为了接受连接而分叉。您可以在一个进程中完成所有操作 - 您只需要确保始终避免阻塞。阅读此beej.us/guide/bgnet/output/html/singlepage/bgnet.html,尤其是关于 select() 的部分。
    猜你喜欢
    • 2015-04-18
    • 2017-12-04
    • 2012-02-12
    • 1970-01-01
    • 1970-01-01
    • 2020-04-16
    • 2022-11-29
    • 2018-06-06
    • 2023-02-06
    相关资源
    最近更新 更多