c++选择问题

发布于 2024-10-31 23:33:47 字数 1311 浏览 1 评论 0原文

所以我正在尝试构建一个异步服务器...这是迄今为止我所拥有的内容的摘要:

int sockfd;
int max;
fd_set socks;
set<int> conns;

bind();
listen(sockfd);

while(1){
    FD_ZERO(&socks);
    max = sockfd;
    FD_SET(sockfd, &socks);
    for(set<int>::iterator it=conns.begin(); it!=conns.end(); it++){
        FD_SET(*it, &socks);
        if(max < *it){
            max = *it;
        }
    }

    int res = select(max+1, &socks, NULL, NULL, NULL);

    if(res < 0){
        cerr << "ERROR with select" << endl;
        break;
    }else if(res){
        if(FD_ISSET(sockfd, &socks)){
            //new connection
            int new_sockfd = accept();
            conns.insert(new_sockfd);
        }else{
            for(set<int>::iterator it=conns.begin(); it!=conns.end(); it++){
                if(FD_ISSET(*it, &socks){
                    char buffer[256];
                    read(buffer, 256, *it);
                    cout << buffer << endl;
                    close(*it);
                    conns.erase(*it);
                }
            }
        }
    }
}

最终发生的事情是...如果我连接客户端 1,然后连接客户端 2。然后我尝试使用 Client-2 然后 Client-1 发送数据...它有效...

但是,如果我连接 client-1 然后连接 client-2...然后尝试使用 client- 发送数据1. Select() 返回 -1...

有帮助吗?

So I'm trying to build a async server... Here is a summary of what I have so far:

int sockfd;
int max;
fd_set socks;
set<int> conns;

bind();
listen(sockfd);

while(1){
    FD_ZERO(&socks);
    max = sockfd;
    FD_SET(sockfd, &socks);
    for(set<int>::iterator it=conns.begin(); it!=conns.end(); it++){
        FD_SET(*it, &socks);
        if(max < *it){
            max = *it;
        }
    }

    int res = select(max+1, &socks, NULL, NULL, NULL);

    if(res < 0){
        cerr << "ERROR with select" << endl;
        break;
    }else if(res){
        if(FD_ISSET(sockfd, &socks)){
            //new connection
            int new_sockfd = accept();
            conns.insert(new_sockfd);
        }else{
            for(set<int>::iterator it=conns.begin(); it!=conns.end(); it++){
                if(FD_ISSET(*it, &socks){
                    char buffer[256];
                    read(buffer, 256, *it);
                    cout << buffer << endl;
                    close(*it);
                    conns.erase(*it);
                }
            }
        }
    }
}

What ends up happening is... If I connect a client-1, and then client-2. And then I try and send data using Client-2 and then Client-1... it works...

However, If I connect client-1 and then connect client-2... and then try to send data using client-1. Select() returns a -1...

Help?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

莫相离 2024-11-07 23:33:47

查看 select 的手册页。重要的部分是:

在以下条件下,pselect() 和 select() 将失败并将 errno 设置为:
EBADF
一个或多个文件描述符集指定的文件描述符不是有效的打开文件描述符。
EINTR
该功能在任何选定事件发生之前和超时间隔到期之前被中断。

如果为中断信号设置了 SA_RESTART,则函数是否重新启动或返回 [EINTR] 由实现定义。
EINVAL
指定的超时间隔无效。
EINVAL
nfds 参数小于 0 或大于 FD_SETSIZE。
EINVAL
指定的文件描述符之一指的是从多路复用器下游链接(直接或间接)的 STREAM 或多路复用器。

errno 应该告诉你出了什么问题。

这只是一个问题,但是当您关闭连接时,您的文件描述符将变得无效。我猜 select 的错误应该是 EBADF

Take a look into man pages for select. The important part is :

Under the following conditions, pselect() and select() shall fail and set errno to:
EBADF
One or more of the file descriptor sets specified a file descriptor that is not a valid open file descriptor.
EINTR
The function was interrupted before any of the selected events occurred and before the timeout interval expired.

If SA_RESTART has been set for the interrupting signal, it is implementation-defined whether the function restarts or returns with [EINTR].
EINVAL
An invalid timeout interval was specified.
EINVAL
The nfds argument is less than 0 or greater than FD_SETSIZE.
EINVAL
One of the specified file descriptors refers to a STREAM or multiplexer that is linked (directly or indirectly) downstream from a multiplexer.

errno should tell you what is wrong.

This is just a quess, but when you close the connection, your file descriptor becomes invalid. I guess the error from select should be EBADF

你好,陌生人 2024-11-07 23:33:47

我认为你的代码从集合中删除是可疑的。一旦你调用conns.erase(*it),你的迭代器就无效了(并且增加它会导致未定义的行为)。

将循环更改为如下所示应该可以解决问题:

for(set<int>::iterator it=conns.begin(); it!=conns.end();)
{
    set<int>::iterator cur = it++;
    if(FD_ISSET(*cur, &socks)){
        char buffer[256];
        read(buffer, 256, *cur);
        cout << buffer << endl;
        close(*cur);
        conns.erase(*cur);
    }
}

I think your code erasing from the set is suspect. once you call conns.erase(*it), your iterator is invalid (and incrementing it leads to undefined behavior).

Changing your loop to something like the following should resolve the issue:

for(set<int>::iterator it=conns.begin(); it!=conns.end();)
{
    set<int>::iterator cur = it++;
    if(FD_ISSET(*cur, &socks)){
        char buffer[256];
        read(buffer, 256, *cur);
        cout << buffer << endl;
        close(*cur);
        conns.erase(*cur);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文