首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在C++ networking中,使用select do I first have to listen()和accept()?

在C++ networking中,使用select do I first have to listen()和accept()?
EN

Stack Overflow用户
提问于 2010-02-18 05:10:47
回答 3查看 9.7K关注 0票数 7

我正在尝试允许多个客户端使用select连接到一个主机。我是否必须连接每个端口,告诉它们移动到不同的端口,然后在新端口上重新连接?或者是否会选择允许将多个客户端连接到同一端口?

这是客户端代码:

代码语言:javascript
复制
    int rv;
int sockfd, numbytes;

if ((rv = getaddrinfo(hostName, hostPort, &hints, &servinfo)) != 0) {
    cout << "Could not get server address.\n";
    exit(1);
}

// loop through all the results and connect to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
    if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
        perror("Client: no socket");
        continue;
    }

    if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
        close(sockfd);
        perror("Client: connect");
        continue;
    }

    break;
}

if (p == NULL) {
    fprintf(stderr, "Unable to connect to server.\n");
    exit(2);
}

FD_SET(sockfd, &masterSet);

这是服务器代码:

代码语言:javascript
复制
        int rv = getaddrinfo(NULL, port, &hints, &res);
    int yes = 1;//Not sure what this is for, found it in Beej's
    if(rv != 0){
            cout<< "Error, nothing matches criteria for file descriptor.\n";
            exit(1);
    }
    int fdInit;
    for(temp = res; temp != NULL; temp = temp->ai_next){
            if((fdInit = socket(temp->ai_family, temp->ai_socktype, temp->ai_protocol)) == -1){
                    cout << "This is not the fd you're looking for.  Move along.\n";
                    continue; //This is not the fd you're looking for, move along.
            }

            if(setsockopt(fdInit, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1){
                    cout << "Doom has fallen upon this set socket.\n";
                    perror("setsockopt");
                    exit(1); //Unable to set socket, exit program with code 1
            }

            if(bind(fdInit, temp->ai_addr, temp->ai_addrlen) == -1){
                    cout << "Could not bind fd\n";
                    close(fdInit);
                    continue; //Could not bind fd, continue looking for valid fd
            }
            break; //If a valid fd has been found, stop checking the list
    }
    if(temp==NULL){
            cout<<"Server failed to bind a socket\n";
            exit(2);
    }

    cout << fdInit << endl;
    //Setup the file descriptor for initial connections on specified port
    freeaddrinfo(res);
    FD_SET(fdInit, &masterSet);

任何帮助都是极好的!谢谢。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2010-02-18 05:32:05

TCP连接由连接两端的IP地址和端口号标识。因此,让许多客户机(通常会随机分配端口号)连接到单个服务器端口是很好的。

您创建了一个套接字,并将其bind()到一个端口,在该端口上执行listen()操作,然后等待客户端访问它。如果你不介意阻塞,你可以直接在它上面调用accept(),但你不会做任何超时循环或任何事情。否则,您可以在侦听套接字上执行select(),当客户端尝试连接时,该套接字将变为可读,然后调用accept()

accept()将返回一个新创建的套接字,这是与客户端进行对话的实际套接字。原始的侦听套接字继续侦听,并且可以接受更多的连接。

通常使用select()循环来查看侦听套接字和任何连接的套接字的可读性。然后,当select()返回时,您只需检查侦听套接字是否可读,如果是,则执行accept();否则,查找可读的已连接套接字并处理它。

代码语言:javascript
复制
fd_set fds;
int max = 0, reuse = 1;
struct timeval tv;
int server;
std::vector<int> connected;

// create server listening socket
server = socket(PF_INET, SOCK_STREAM, getprotobyname("tcp")->p_proto);
setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int)); // optional, but recommended
if (bind(server, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) {
    // error, could not bind server socket
}
if (listen(server, 8) < 0) {
    // error, could not listen on server port
}

// loop looking for connections / data to handle
while (running) {
    FD_ZERO(&fds);
    FD_SET(server, &fds);
    if (server >= max) max = server + 1;

    for (std::vector<int>::iterator it = connected.begin(); it != connected.end(); ++it) {
        FD_SET(*it, &fds);
        if (*it >= max) max = *it + 1;
    }

    tv.tv_sec = 2; tv.tv_usec = 0;
    if (select(max, &fds, NULL, NULL, &tv) > 0) {
        // something is readable
        if (FD_ISSET(server, &fds)) {
            // it's the listener
            connected.push_back(accept(server, (struct sockaddr *)&addr));
        }
        for (std::vector<int>::iterator it = connected.begin(); it != connected.end(); ++it) {
            if (FD_ISSET(*it, &fds)) {
                // handle data on this connection
            }
        }
    }
}
票数 13
EN

Stack Overflow用户

发布于 2010-02-18 05:15:25

多个客户端可以连接到同一端口

您必须先听,然后选择

当select提示您有一个新连接时,请接受。它通过标记套接字fd上的读取来告诉您连接的客户端。

票数 3
EN

Stack Overflow用户

发布于 2010-02-18 05:19:22

您必须将服务器套接字标记为此类(listen(2)),但只有在从select(2)返回时accept(2)变得可读时才调用它-这意味着新的连接请求正在等待。

请注意,如果您不使用非阻塞套接字,那么select(2)返回和调用accept(2)之间存在竞争的可能性-连接客户端可能会在这段时间内放弃尝试-因此您仍然可以阻塞。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2284428

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档